clang-format for test files
- Applied format to test files - build tested with gcc-8 / g++-8
This commit is contained in:
parent
8671608b83
commit
2420a589c6
@ -28,9 +28,8 @@ enum class numeric_system {
|
||||
|
||||
// Parses a put_time-like format string and invokes handler actions.
|
||||
template <typename Char, typename Handler>
|
||||
FMT_CONSTEXPR const Char *parse_chrono_format(const Char *begin,
|
||||
const Char *end,
|
||||
Handler &&handler) {
|
||||
FMT_CONSTEXPR const Char *parse_chrono_format(
|
||||
const Char *begin, const Char *end, Handler &&handler) {
|
||||
auto ptr = begin;
|
||||
while (ptr != end) {
|
||||
auto c = *ptr;
|
||||
@ -214,9 +213,10 @@ struct chrono_format_checker {
|
||||
|
||||
template <typename Int>
|
||||
inline int to_int(Int value) {
|
||||
FMT_ASSERT(value >= (std::numeric_limits<int>::min)() &&
|
||||
value <= (std::numeric_limits<int>::max)(),
|
||||
"invalid value");
|
||||
FMT_ASSERT(
|
||||
value >= (std::numeric_limits<int>::min)() &&
|
||||
value <= (std::numeric_limits<int>::max)(),
|
||||
"invalid value");
|
||||
return static_cast<int>(value);
|
||||
}
|
||||
|
||||
@ -491,8 +491,8 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||
format_to(buf, "{}[{}/{}]s", d.count(), Period::num, Period::den);
|
||||
typedef output_range<decltype(ctx.out()), Char> range;
|
||||
basic_writer<range> w(range(ctx.out()));
|
||||
internal::handle_dynamic_spec<internal::width_checker>(spec.width_,
|
||||
width_ref, ctx);
|
||||
internal::handle_dynamic_spec<internal::width_checker>(
|
||||
spec.width_, width_ref, ctx);
|
||||
w.write(buf.data(), buf.size(), spec);
|
||||
return w.out();
|
||||
}
|
||||
|
||||
@ -19,13 +19,13 @@ enum color { black, red, green, yellow, blue, magenta, cyan, white };
|
||||
FMT_API void vprint_colored(color c, string_view format, format_args args);
|
||||
FMT_API void vprint_colored(color c, wstring_view format, wformat_args args);
|
||||
template <typename... Args>
|
||||
inline void print_colored(color c, string_view format_str,
|
||||
const Args&... args) {
|
||||
inline void print_colored(
|
||||
color c, string_view format_str, const Args&... args) {
|
||||
vprint_colored(c, format_str, make_format_args(args...));
|
||||
}
|
||||
template <typename... Args>
|
||||
inline void print_colored(color c, wstring_view format_str,
|
||||
const Args&... args) {
|
||||
inline void print_colored(
|
||||
color c, wstring_view format_str, const Args&... args) {
|
||||
vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
|
||||
}
|
||||
|
||||
@ -290,13 +290,13 @@ class text_style {
|
||||
background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
|
||||
}
|
||||
|
||||
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) |
|
||||
static_cast<uint8_t>(rhs.ems));
|
||||
ems = static_cast<emphasis>(
|
||||
static_cast<uint8_t>(ems) | static_cast<uint8_t>(rhs.ems));
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR text_style operator|(text_style lhs,
|
||||
const text_style &rhs) {
|
||||
friend FMT_CONSTEXPR text_style
|
||||
operator|(text_style lhs, const text_style &rhs) {
|
||||
return lhs |= rhs;
|
||||
}
|
||||
|
||||
@ -319,13 +319,13 @@ class text_style {
|
||||
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
|
||||
}
|
||||
|
||||
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
|
||||
static_cast<uint8_t>(rhs.ems));
|
||||
ems = static_cast<emphasis>(
|
||||
static_cast<uint8_t>(ems) & static_cast<uint8_t>(rhs.ems));
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR text_style operator&(text_style lhs,
|
||||
const text_style &rhs) {
|
||||
friend FMT_CONSTEXPR text_style
|
||||
operator&(text_style lhs, const text_style &rhs) {
|
||||
return lhs &= rhs;
|
||||
}
|
||||
|
||||
@ -352,11 +352,10 @@ class text_style {
|
||||
}
|
||||
|
||||
private:
|
||||
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||
internal::color_type text_color) FMT_NOEXCEPT
|
||||
: set_foreground_color(),
|
||||
set_background_color(),
|
||||
ems() {
|
||||
FMT_CONSTEXPR text_style(bool is_foreground, internal::color_type text_color)
|
||||
FMT_NOEXCEPT : set_foreground_color(),
|
||||
set_background_color(),
|
||||
ems() {
|
||||
if (is_foreground) {
|
||||
foreground_color = text_color;
|
||||
set_foreground_color = true;
|
||||
@ -394,8 +393,8 @@ namespace internal {
|
||||
|
||||
template <typename Char>
|
||||
struct ansi_color_escape {
|
||||
FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
|
||||
const char *esc) FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR ansi_color_escape(
|
||||
internal::color_type text_color, const char *esc) FMT_NOEXCEPT {
|
||||
// If we have a terminal color, we need to output another escape code
|
||||
// sequence.
|
||||
if (!text_color.is_rgb) {
|
||||
@ -459,8 +458,8 @@ struct ansi_color_escape {
|
||||
private:
|
||||
Char buffer[7 + 3 * 4 + 1];
|
||||
|
||||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out,
|
||||
char delimiter) FMT_NOEXCEPT {
|
||||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out, char delimiter)
|
||||
FMT_NOEXCEPT {
|
||||
out[0] = static_cast<Char>('0' + c / 100);
|
||||
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||
out[2] = static_cast<Char>('0' + c % 10);
|
||||
@ -516,8 +515,11 @@ struct is_string<const std::FILE *> : std::false_type {};
|
||||
} // namespace internal
|
||||
|
||||
template <typename S, typename Char = typename internal::char_t<S>::type>
|
||||
void vprint(std::FILE *f, const text_style &ts, const S &format,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
void vprint(
|
||||
std::FILE *f,
|
||||
const text_style &ts,
|
||||
const S &format,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
bool has_style = false;
|
||||
if (ts.has_emphasis()) {
|
||||
has_style = true;
|
||||
@ -548,7 +550,9 @@ void vprint(std::FILE *f, const text_style &ts, const S &format,
|
||||
*/
|
||||
template <typename String, typename... Args>
|
||||
typename std::enable_if<internal::is_string<String>::value>::type print(
|
||||
std::FILE *f, const text_style &ts, const String &format_str,
|
||||
std::FILE *f,
|
||||
const text_style &ts,
|
||||
const String &format_str,
|
||||
const Args &... args) {
|
||||
internal::check_format_string<Args...>(format_str);
|
||||
typedef typename internal::char_t<String>::type char_t;
|
||||
|
||||
@ -178,8 +178,9 @@
|
||||
#endif
|
||||
|
||||
// libc++ supports string_view in pre-c++17.
|
||||
#if (FMT_HAS_INCLUDE(<string_view>) && \
|
||||
(__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \
|
||||
#if ( \
|
||||
FMT_HAS_INCLUDE(<string_view>) && \
|
||||
(__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \
|
||||
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
|
||||
#include <string_view>
|
||||
#define FMT_STRING_VIEW std::basic_string_view
|
||||
@ -232,10 +233,10 @@ class basic_buffer {
|
||||
// Don't initialize ptr_ since it is not accessed to save a few cycles.
|
||||
basic_buffer(std::size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {}
|
||||
|
||||
basic_buffer(T *p = FMT_NULL, std::size_t sz = 0,
|
||||
std::size_t cap = 0) FMT_NOEXCEPT : ptr_(p),
|
||||
size_(sz),
|
||||
capacity_(cap) {}
|
||||
basic_buffer(T *p = FMT_NULL, std::size_t sz = 0, std::size_t cap = 0)
|
||||
FMT_NOEXCEPT : ptr_(p),
|
||||
size_(sz),
|
||||
capacity_(cap) {}
|
||||
|
||||
/** Sets the buffer data and capacity. */
|
||||
void set(T *buf_data, std::size_t buf_capacity) FMT_NOEXCEPT {
|
||||
@ -491,8 +492,10 @@ struct compile_string {};
|
||||
template <typename S>
|
||||
struct is_compile_string : std::is_base_of<compile_string, S> {};
|
||||
|
||||
template <typename S, typename Enable = typename std::enable_if<
|
||||
is_compile_string<S>::value>::type>
|
||||
template <
|
||||
typename S,
|
||||
typename Enable =
|
||||
typename std::enable_if<is_compile_string<S>::value>::type>
|
||||
FMT_CONSTEXPR basic_string_view<typename S::char_type> to_string_view(
|
||||
const S &s) {
|
||||
return s;
|
||||
@ -521,8 +524,10 @@ struct formatter {
|
||||
|
||||
template <typename T, typename Char, typename Enable = void>
|
||||
struct convert_to_int
|
||||
: std::integral_constant<bool, !std::is_arithmetic<T>::value &&
|
||||
std::is_convertible<T, int>::value> {};
|
||||
: std::integral_constant<
|
||||
bool,
|
||||
!std::is_arithmetic<T>::value && std::is_convertible<T, int>::value> {
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
@ -534,11 +539,11 @@ using fmt::v5::to_string_view;
|
||||
|
||||
// Specifies whether S is a string type convertible to fmt::basic_string_view.
|
||||
template <typename S>
|
||||
struct is_string
|
||||
: std::integral_constant<
|
||||
bool, !std::is_same<dummy_string_view,
|
||||
decltype(to_string_view(declval<S>()))>::value> {
|
||||
};
|
||||
struct is_string : std::integral_constant<
|
||||
bool,
|
||||
!std::is_same<
|
||||
dummy_string_view,
|
||||
decltype(to_string_view(declval<S>()))>::value> {};
|
||||
|
||||
template <typename S>
|
||||
struct char_t {
|
||||
@ -623,13 +628,13 @@ class value {
|
||||
value(long double val) { long_double_value = val; }
|
||||
value(const char_type *val) { string.value = val; }
|
||||
value(const signed char *val) {
|
||||
static_assert(std::is_same<char, char_type>::value,
|
||||
"incompatible string types");
|
||||
static_assert(
|
||||
std::is_same<char, char_type>::value, "incompatible string types");
|
||||
sstring.value = val;
|
||||
}
|
||||
value(const unsigned char *val) {
|
||||
static_assert(std::is_same<char, char_type>::value,
|
||||
"incompatible string types");
|
||||
static_assert(
|
||||
std::is_same<char, char_type>::value, "incompatible string types");
|
||||
ustring.value = val;
|
||||
}
|
||||
value(basic_string_view<char_type> val) {
|
||||
@ -697,13 +702,16 @@ FMT_MAKE_VALUE_SAME(uint_type, unsigned)
|
||||
// either to int or to long long depending on its size.
|
||||
typedef std::conditional<sizeof(long) == sizeof(int), int, long long>::type
|
||||
long_type;
|
||||
FMT_MAKE_VALUE((sizeof(long) == sizeof(int) ? int_type : long_long_type), long,
|
||||
long_type)
|
||||
typedef std::conditional<sizeof(unsigned long) == sizeof(unsigned), unsigned,
|
||||
unsigned long long>::type ulong_type;
|
||||
FMT_MAKE_VALUE((sizeof(unsigned long) == sizeof(unsigned) ? uint_type
|
||||
: ulong_long_type),
|
||||
unsigned long, ulong_type)
|
||||
FMT_MAKE_VALUE(
|
||||
(sizeof(long) == sizeof(int) ? int_type : long_long_type), long, long_type)
|
||||
typedef std::conditional<
|
||||
sizeof(unsigned long) == sizeof(unsigned),
|
||||
unsigned,
|
||||
unsigned long long>::type ulong_type;
|
||||
FMT_MAKE_VALUE(
|
||||
(sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type),
|
||||
unsigned long,
|
||||
ulong_type)
|
||||
|
||||
FMT_MAKE_VALUE_SAME(long_long_type, long long)
|
||||
FMT_MAKE_VALUE_SAME(ulong_long_type, unsigned long long)
|
||||
@ -712,18 +720,18 @@ FMT_MAKE_VALUE(uint_type, unsigned char, unsigned)
|
||||
|
||||
// This doesn't use FMT_MAKE_VALUE because of ambiguity in gcc 4.4.
|
||||
template <typename C, typename Char>
|
||||
FMT_CONSTEXPR
|
||||
typename std::enable_if<std::is_same<typename C::char_type, Char>::value,
|
||||
init<C, int, char_type>>::type
|
||||
make_value(Char val) {
|
||||
FMT_CONSTEXPR typename std::enable_if<
|
||||
std::is_same<typename C::char_type, Char>::value,
|
||||
init<C, int, char_type>>::type
|
||||
make_value(Char val) {
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
FMT_CONSTEXPR
|
||||
typename std::enable_if<!std::is_same<typename C::char_type, char>::value,
|
||||
init<C, int, char_type>>::type
|
||||
make_value(char val) {
|
||||
FMT_CONSTEXPR typename std::enable_if<
|
||||
!std::is_same<typename C::char_type, char>::value,
|
||||
init<C, int, char_type>>::type
|
||||
make_value(char val) {
|
||||
return val;
|
||||
}
|
||||
|
||||
@ -733,21 +741,24 @@ FMT_MAKE_VALUE_SAME(long_double_type, long double)
|
||||
|
||||
// Formatting of wide strings into a narrow buffer and multibyte strings
|
||||
// into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606).
|
||||
FMT_MAKE_VALUE(cstring_type, typename C::char_type *,
|
||||
const typename C::char_type *)
|
||||
FMT_MAKE_VALUE(cstring_type, const typename C::char_type *,
|
||||
const typename C::char_type *)
|
||||
FMT_MAKE_VALUE(
|
||||
cstring_type, typename C::char_type *, const typename C::char_type *)
|
||||
FMT_MAKE_VALUE(
|
||||
cstring_type, const typename C::char_type *, const typename C::char_type *)
|
||||
|
||||
FMT_MAKE_VALUE(cstring_type, signed char *, const signed char *)
|
||||
FMT_MAKE_VALUE_SAME(cstring_type, const signed char *)
|
||||
FMT_MAKE_VALUE(cstring_type, unsigned char *, const unsigned char *)
|
||||
FMT_MAKE_VALUE_SAME(cstring_type, const unsigned char *)
|
||||
FMT_MAKE_VALUE_SAME(string_type, basic_string_view<typename C::char_type>)
|
||||
FMT_MAKE_VALUE(string_type,
|
||||
typename basic_string_view<typename C::char_type>::type,
|
||||
basic_string_view<typename C::char_type>)
|
||||
FMT_MAKE_VALUE(string_type, const std::basic_string<typename C::char_type> &,
|
||||
basic_string_view<typename C::char_type>)
|
||||
FMT_MAKE_VALUE(
|
||||
string_type,
|
||||
typename basic_string_view<typename C::char_type>::type,
|
||||
basic_string_view<typename C::char_type>)
|
||||
FMT_MAKE_VALUE(
|
||||
string_type,
|
||||
const std::basic_string<typename C::char_type> &,
|
||||
basic_string_view<typename C::char_type>)
|
||||
FMT_MAKE_VALUE(pointer_type, void *, const void *)
|
||||
FMT_MAKE_VALUE_SAME(pointer_type, const void *)
|
||||
|
||||
@ -766,11 +777,10 @@ make_value(const T *) {
|
||||
}
|
||||
|
||||
template <typename C, typename T>
|
||||
inline
|
||||
typename std::enable_if<std::is_enum<T>::value &&
|
||||
convert_to_int<T, typename C::char_type>::value,
|
||||
init<C, int, int_type>>::type
|
||||
make_value(const T &val) {
|
||||
inline typename std::enable_if<
|
||||
std::is_enum<T>::value && convert_to_int<T, typename C::char_type>::value,
|
||||
init<C, int, int_type>>::type
|
||||
make_value(const T &val) {
|
||||
return static_cast<int>(val);
|
||||
}
|
||||
|
||||
@ -810,9 +820,10 @@ FMT_CONSTEXPR11 typename std::enable_if<
|
||||
init<C, basic_string_view<typename C::char_type>, string_type>>::type
|
||||
make_value(const S &val) {
|
||||
// Handle adapted strings.
|
||||
static_assert(std::is_same<typename C::char_type,
|
||||
typename internal::char_t<S>::type>::value,
|
||||
"mismatch between char-types of context and argument");
|
||||
static_assert(
|
||||
std::is_same<typename C::char_type, typename internal::char_t<S>::type>::
|
||||
value,
|
||||
"mismatch between char-types of context and argument");
|
||||
return to_string_view(val);
|
||||
}
|
||||
|
||||
@ -906,8 +917,8 @@ FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type visit_format_arg(
|
||||
case internal::cstring_type:
|
||||
return vis(arg.value_.string.value);
|
||||
case internal::string_type:
|
||||
return vis(basic_string_view<char_type>(arg.value_.string.value,
|
||||
arg.value_.string.size));
|
||||
return vis(basic_string_view<char_type>(
|
||||
arg.value_.string.value, arg.value_.string.size));
|
||||
case internal::pointer_type:
|
||||
return vis(arg.value_.pointer);
|
||||
case internal::custom_type:
|
||||
@ -934,8 +945,8 @@ class basic_parse_context : private ErrorHandler {
|
||||
typedef Char char_type;
|
||||
typedef typename basic_string_view<Char>::iterator iterator;
|
||||
|
||||
explicit FMT_CONSTEXPR basic_parse_context(basic_string_view<Char> format_str,
|
||||
ErrorHandler eh = ErrorHandler())
|
||||
explicit FMT_CONSTEXPR basic_parse_context(
|
||||
basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler())
|
||||
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}
|
||||
|
||||
// Returns an iterator to the beginning of the format string range being
|
||||
@ -1049,9 +1060,11 @@ class context_base {
|
||||
typedef Char char_type;
|
||||
typedef basic_format_arg<Context> format_arg;
|
||||
|
||||
context_base(OutputIt out, basic_string_view<char_type> format_str,
|
||||
basic_format_args<Context> ctx_args,
|
||||
locale_ref loc = locale_ref())
|
||||
context_base(
|
||||
OutputIt out,
|
||||
basic_string_view<char_type> format_str,
|
||||
basic_format_args<Context> ctx_args,
|
||||
locale_ref loc = locale_ref())
|
||||
: parse_context_(format_str), out_(out), args_(ctx_args), loc_(loc) {}
|
||||
|
||||
// Returns the argument with specified index.
|
||||
@ -1131,8 +1144,8 @@ make_arg(const T &value) {
|
||||
// Formatting context.
|
||||
template <typename OutputIt, typename Char>
|
||||
class basic_format_context
|
||||
: public internal::context_base<
|
||||
OutputIt, basic_format_context<OutputIt, Char>, Char> {
|
||||
: public internal::
|
||||
context_base<OutputIt, basic_format_context<OutputIt, Char>, Char> {
|
||||
public:
|
||||
/** The character type for the output. */
|
||||
typedef Char char_type;
|
||||
@ -1160,9 +1173,11 @@ class basic_format_context
|
||||
Constructs a ``basic_format_context`` object. References to the arguments are
|
||||
stored in the object so make sure they have appropriate lifetimes.
|
||||
*/
|
||||
basic_format_context(OutputIt out, basic_string_view<char_type> format_str,
|
||||
basic_format_args<basic_format_context> ctx_args,
|
||||
internal::locale_ref loc = internal::locale_ref())
|
||||
basic_format_context(
|
||||
OutputIt out,
|
||||
basic_string_view<char_type> format_str,
|
||||
basic_format_args<basic_format_context> ctx_args,
|
||||
internal::locale_ref loc = internal::locale_ref())
|
||||
: base(out, format_str, ctx_args, loc) {}
|
||||
|
||||
format_arg next_arg() {
|
||||
@ -1178,7 +1193,8 @@ class basic_format_context
|
||||
template <typename Char>
|
||||
struct buffer_context {
|
||||
typedef basic_format_context<
|
||||
std::back_insert_iterator<internal::basic_buffer<Char>>, Char>
|
||||
std::back_insert_iterator<internal::basic_buffer<Char>>,
|
||||
Char>
|
||||
type;
|
||||
};
|
||||
typedef buffer_context<char>::type format_context;
|
||||
@ -1199,8 +1215,10 @@ class format_arg_store {
|
||||
// Packed is a macro on MinGW so use IS_PACKED instead.
|
||||
static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args;
|
||||
|
||||
typedef typename std::conditional<IS_PACKED, internal::value<Context>,
|
||||
basic_format_arg<Context>>::type value_type;
|
||||
typedef typename std::conditional<
|
||||
IS_PACKED,
|
||||
internal::value<Context>,
|
||||
basic_format_arg<Context>>::type value_type;
|
||||
|
||||
// If the arguments are not packed, add one more element to mark the end.
|
||||
static const size_t DATA_SIZE =
|
||||
@ -1279,8 +1297,8 @@ class basic_format_args {
|
||||
|
||||
typename internal::type type(unsigned index) const {
|
||||
unsigned shift = index * 4;
|
||||
return static_cast<typename internal::type>((types_ & (0xfull << shift)) >>
|
||||
shift);
|
||||
return static_cast<typename internal::type>(
|
||||
(types_ & (0xfull << shift)) >> shift);
|
||||
}
|
||||
|
||||
friend class internal::arg_map<Context>;
|
||||
@ -1366,13 +1384,14 @@ struct wformat_args : basic_format_args<wformat_context> {
|
||||
#if FMT_USE_ALIAS_TEMPLATES
|
||||
/** String's character type. */
|
||||
template <typename S>
|
||||
using char_t = FMT_ENABLE_IF_T(internal::is_string<S>::value,
|
||||
typename internal::char_t<S>::type);
|
||||
using char_t = FMT_ENABLE_IF_T(
|
||||
internal::is_string<S>::value, typename internal::char_t<S>::type);
|
||||
#define FMT_CHAR(S) fmt::char_t<S>
|
||||
#else
|
||||
template <typename S>
|
||||
struct char_t : std::enable_if<internal::is_string<S>::value,
|
||||
typename internal::char_t<S>::type> {};
|
||||
struct char_t : std::enable_if<
|
||||
internal::is_string<S>::value,
|
||||
typename internal::char_t<S>::type> {};
|
||||
#define FMT_CHAR(S) typename char_t<S>::type
|
||||
#endif
|
||||
|
||||
@ -1430,7 +1449,8 @@ std::basic_string<Char> vformat(
|
||||
|
||||
template <typename Char>
|
||||
typename buffer_context<Char>::type::iterator vformat_to(
|
||||
internal::basic_buffer<Char> &buf, basic_string_view<Char> format_str,
|
||||
internal::basic_buffer<Char> &buf,
|
||||
basic_string_view<Char> format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args);
|
||||
} // namespace internal
|
||||
|
||||
@ -1468,21 +1488,26 @@ struct is_contiguous<internal::basic_buffer<Char>> : std::true_type {};
|
||||
|
||||
/** Formats a string and writes the output to ``out``. */
|
||||
template <typename Container, typename S>
|
||||
typename std::enable_if<is_contiguous<Container>::value,
|
||||
std::back_insert_iterator<Container>>::type
|
||||
vformat_to(std::back_insert_iterator<Container> out, const S &format_str,
|
||||
basic_format_args<typename buffer_context<FMT_CHAR(S)>::type> args) {
|
||||
typename std::enable_if<
|
||||
is_contiguous<Container>::value,
|
||||
std::back_insert_iterator<Container>>::type
|
||||
vformat_to(
|
||||
std::back_insert_iterator<Container> out,
|
||||
const S &format_str,
|
||||
basic_format_args<typename buffer_context<FMT_CHAR(S)>::type> args) {
|
||||
internal::container_buffer<Container> buf(internal::get_container(out));
|
||||
internal::vformat_to(buf, to_string_view(format_str), args);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename Container, typename S, typename... Args>
|
||||
inline typename std::enable_if<is_contiguous<Container>::value &&
|
||||
internal::is_string<S>::value,
|
||||
std::back_insert_iterator<Container>>::type
|
||||
format_to(std::back_insert_iterator<Container> out, const S &format_str,
|
||||
const Args &... args) {
|
||||
inline typename std::enable_if<
|
||||
is_contiguous<Container>::value && internal::is_string<S>::value,
|
||||
std::back_insert_iterator<Container>>::type
|
||||
format_to(
|
||||
std::back_insert_iterator<Container> out,
|
||||
const S &format_str,
|
||||
const Args &... args) {
|
||||
internal::checked_args<S, Args...> ca(format_str, args...);
|
||||
return vformat_to(out, to_string_view(format_str), *ca);
|
||||
}
|
||||
@ -1505,8 +1530,8 @@ inline std::basic_string<Char> vformat(
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args>
|
||||
inline std::basic_string<FMT_CHAR(S)> format(const S &format_str,
|
||||
const Args &... args) {
|
||||
inline std::basic_string<FMT_CHAR(S)> format(
|
||||
const S &format_str, const Args &... args) {
|
||||
return internal::vformat(
|
||||
to_string_view(format_str),
|
||||
*internal::checked_args<S, Args...>(format_str, args...));
|
||||
@ -1529,8 +1554,10 @@ FMT_API void vprint(std::FILE *f, wstring_view format_str, wformat_args args);
|
||||
template <typename S, typename... Args>
|
||||
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, void)
|
||||
print(std::FILE *f, const S &format_str, const Args &... args) {
|
||||
vprint(f, to_string_view(format_str),
|
||||
internal::checked_args<S, Args...>(format_str, args...));
|
||||
vprint(
|
||||
f,
|
||||
to_string_view(format_str),
|
||||
internal::checked_args<S, Args...>(format_str, args...));
|
||||
}
|
||||
|
||||
FMT_API void vprint(string_view format_str, format_args args);
|
||||
@ -1548,8 +1575,9 @@ FMT_API void vprint(wstring_view format_str, wformat_args args);
|
||||
template <typename S, typename... Args>
|
||||
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, void)
|
||||
print(const S &format_str, const Args &... args) {
|
||||
vprint(to_string_view(format_str),
|
||||
internal::checked_args<S, Args...>(format_str, args...));
|
||||
vprint(
|
||||
to_string_view(format_str),
|
||||
internal::checked_args<S, Args...>(format_str, args...));
|
||||
}
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
|
||||
@ -95,8 +95,8 @@ typedef void (*FormatFunc)(internal::buffer &, int, string_view);
|
||||
// ERANGE - buffer is not large enough to store the error message
|
||||
// other - failure
|
||||
// Buffer should be at least of size 1.
|
||||
int safe_strerror(int error_code, char *&buffer,
|
||||
std::size_t buffer_size) FMT_NOEXCEPT {
|
||||
int safe_strerror(int error_code, char *&buffer, std::size_t buffer_size)
|
||||
FMT_NOEXCEPT {
|
||||
FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
|
||||
|
||||
class dispatcher {
|
||||
@ -153,8 +153,8 @@ int safe_strerror(int error_code, char *&buffer,
|
||||
return dispatcher(error_code, buffer, buffer_size).run();
|
||||
}
|
||||
|
||||
void format_error_code(internal::buffer &out, int error_code,
|
||||
string_view message) FMT_NOEXCEPT {
|
||||
void format_error_code(
|
||||
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
|
||||
// Report error code making sure that the output fits into
|
||||
// inline_buffer_size to avoid dynamic memory allocation and potential
|
||||
// bad_alloc.
|
||||
@ -180,8 +180,8 @@ void format_error_code(internal::buffer &out, int error_code,
|
||||
assert(out.size() <= inline_buffer_size);
|
||||
}
|
||||
|
||||
void report_error(FormatFunc func, int error_code,
|
||||
string_view message) FMT_NOEXCEPT {
|
||||
void report_error(FormatFunc func, int error_code, string_view message)
|
||||
FMT_NOEXCEPT {
|
||||
memory_buffer full_message;
|
||||
func(full_message, error_code, message);
|
||||
// Use Writer::data instead of Writer::c_str to avoid potential memory
|
||||
@ -228,8 +228,8 @@ FMT_FUNC Char internal::thousands_sep_impl(locale_ref) {
|
||||
}
|
||||
#endif
|
||||
|
||||
FMT_FUNC void system_error::init(int err_code, string_view format_str,
|
||||
format_args args) {
|
||||
FMT_FUNC void system_error::init(
|
||||
int err_code, string_view format_str, format_args args) {
|
||||
error_code_ = err_code;
|
||||
memory_buffer buffer;
|
||||
format_system_error(buffer, err_code, vformat(format_str, args));
|
||||
@ -239,17 +239,19 @@ FMT_FUNC void system_error::init(int err_code, string_view format_str,
|
||||
|
||||
namespace internal {
|
||||
template <typename T>
|
||||
int char_traits<char>::format_float(char *buf, std::size_t size,
|
||||
const char *format, int precision,
|
||||
T value) {
|
||||
int char_traits<char>::format_float(
|
||||
char *buf, std::size_t size, const char *format, int precision, T value) {
|
||||
return precision < 0 ? FMT_SNPRINTF(buf, size, format, value)
|
||||
: FMT_SNPRINTF(buf, size, format, precision, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int char_traits<wchar_t>::format_float(wchar_t *buf, std::size_t size,
|
||||
const wchar_t *format, int precision,
|
||||
T value) {
|
||||
int char_traits<wchar_t>::format_float(
|
||||
wchar_t *buf,
|
||||
std::size_t size,
|
||||
const wchar_t *format,
|
||||
int precision,
|
||||
T value) {
|
||||
return precision < 0 ? FMT_SWPRINTF(buf, size, format, value)
|
||||
: FMT_SWPRINTF(buf, size, format, precision, value);
|
||||
}
|
||||
@ -276,7 +278,9 @@ const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {0,
|
||||
|
||||
template <typename T>
|
||||
const uint64_t basic_data<T>::ZERO_OR_POWERS_OF_10_64[] = {
|
||||
0, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(1000000000ull),
|
||||
0,
|
||||
FMT_POWERS_OF_10(1),
|
||||
FMT_POWERS_OF_10(1000000000ull),
|
||||
10000000000000000000ull};
|
||||
|
||||
// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
|
||||
@ -451,9 +455,15 @@ FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
|
||||
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
|
||||
}
|
||||
|
||||
FMT_FUNC bool grisu2_round(char *buf, ptrdiff_t &size, size_t max_digits,
|
||||
uint64_t delta, uint64_t remainder, uint64_t exp,
|
||||
uint64_t diff, int &exp10) {
|
||||
FMT_FUNC bool grisu2_round(
|
||||
char *buf,
|
||||
ptrdiff_t &size,
|
||||
size_t max_digits,
|
||||
uint64_t delta,
|
||||
uint64_t remainder,
|
||||
uint64_t exp,
|
||||
uint64_t diff,
|
||||
int &exp10) {
|
||||
while (
|
||||
remainder < diff && delta - remainder >= exp &&
|
||||
(remainder + exp < diff || diff - remainder > remainder + exp - diff)) {
|
||||
@ -470,10 +480,16 @@ FMT_FUNC bool grisu2_round(char *buf, ptrdiff_t &size, size_t max_digits,
|
||||
}
|
||||
|
||||
// Generates output using Grisu2 digit-gen algorithm.
|
||||
FMT_FUNC bool grisu2_gen_digits(char *buf, ptrdiff_t &size, uint32_t hi,
|
||||
uint64_t lo, int &exp, uint64_t delta,
|
||||
const fp &one, const fp &diff,
|
||||
size_t max_digits) {
|
||||
FMT_FUNC bool grisu2_gen_digits(
|
||||
char *buf,
|
||||
ptrdiff_t &size,
|
||||
uint32_t hi,
|
||||
uint64_t lo,
|
||||
int &exp,
|
||||
uint64_t delta,
|
||||
const fp &one,
|
||||
const fp &diff,
|
||||
size_t max_digits) {
|
||||
// Generate digits for the most significant part (hi).
|
||||
while (exp > 0) {
|
||||
uint32_t digit = 0;
|
||||
@ -529,8 +545,13 @@ FMT_FUNC bool grisu2_gen_digits(char *buf, ptrdiff_t &size, uint32_t hi,
|
||||
uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
|
||||
if (remainder <= delta || size > static_cast<ptrdiff_t>(max_digits)) {
|
||||
return grisu2_round(
|
||||
buf, size, max_digits, delta, remainder,
|
||||
static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e, diff.f,
|
||||
buf,
|
||||
size,
|
||||
max_digits,
|
||||
delta,
|
||||
remainder,
|
||||
static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e,
|
||||
diff.f,
|
||||
exp);
|
||||
}
|
||||
}
|
||||
@ -544,8 +565,15 @@ FMT_FUNC bool grisu2_gen_digits(char *buf, ptrdiff_t &size, uint32_t hi,
|
||||
lo &= one.f - 1;
|
||||
--exp;
|
||||
if (lo < delta || size > static_cast<ptrdiff_t>(max_digits)) {
|
||||
return grisu2_round(buf, size, max_digits, delta, lo, one.f,
|
||||
diff.f * data::POWERS_OF_10_32[-exp], exp);
|
||||
return grisu2_round(
|
||||
buf,
|
||||
size,
|
||||
max_digits,
|
||||
delta,
|
||||
lo,
|
||||
one.f,
|
||||
diff.f * data::POWERS_OF_10_32[-exp],
|
||||
exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -636,8 +664,8 @@ struct fill {
|
||||
|
||||
// The number is given as v = f * pow(10, exp), where f has size digits.
|
||||
template <typename Handler>
|
||||
FMT_FUNC void grisu2_prettify(const gen_digits_params ¶ms, int size,
|
||||
int exp, Handler &&handler) {
|
||||
FMT_FUNC void grisu2_prettify(
|
||||
const gen_digits_params ¶ms, int size, int exp, Handler &&handler) {
|
||||
if (!params.fixed) {
|
||||
// Insert a decimal point after the first digit and add an exponent.
|
||||
handler.insert(1, '.');
|
||||
@ -692,8 +720,8 @@ struct char_counter {
|
||||
// Converts format specifiers into parameters for digit generation and computes
|
||||
// output buffer size for a number in the range [pow(10, exp - 1), pow(10, exp)
|
||||
// or 0 if exp == 1.
|
||||
FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,
|
||||
int exp, buffer &buf) {
|
||||
FMT_FUNC gen_digits_params
|
||||
process_specs(const core_format_specs &specs, int exp, buffer &buf) {
|
||||
auto params = gen_digits_params();
|
||||
int num_digits = specs.precision >= 0 ? specs.precision : 6;
|
||||
switch (specs.type) {
|
||||
@ -754,7 +782,8 @@ grisu2_format(Double value, buffer &buf, core_format_specs specs) {
|
||||
const int min_exp = -60; // alpha in Grisu.
|
||||
int cached_exp = 0; // K in Grisu.
|
||||
auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
|
||||
min_exp - (upper.e + fp::significand_size), cached_exp);
|
||||
min_exp - (upper.e + fp::significand_size),
|
||||
cached_exp);
|
||||
cached_exp = -cached_exp;
|
||||
upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
|
||||
--upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
|
||||
@ -774,8 +803,8 @@ grisu2_format(Double value, buffer &buf, core_format_specs specs) {
|
||||
// lo = supper % one.
|
||||
uint64_t lo = upper.f & (one.f - 1);
|
||||
ptrdiff_t size = 0;
|
||||
if (!grisu2_gen_digits(buf.data(), size, hi, lo, exp, delta, one, diff,
|
||||
params.num_digits)) {
|
||||
if (!grisu2_gen_digits(
|
||||
buf.data(), size, hi, lo, exp, delta, one, diff, params.num_digits)) {
|
||||
buf.clear();
|
||||
return false;
|
||||
}
|
||||
@ -784,8 +813,8 @@ grisu2_format(Double value, buffer &buf, core_format_specs specs) {
|
||||
}
|
||||
|
||||
template <typename Double>
|
||||
void sprintf_format(Double value, internal::buffer &buf,
|
||||
core_format_specs spec) {
|
||||
void sprintf_format(
|
||||
Double value, internal::buffer &buf, core_format_specs spec) {
|
||||
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
|
||||
FMT_ASSERT(buf.capacity() != 0, "empty buffer");
|
||||
|
||||
@ -842,13 +871,13 @@ FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
|
||||
return;
|
||||
}
|
||||
|
||||
int length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(),
|
||||
s_size, FMT_NULL, 0);
|
||||
int length = MultiByteToWideChar(
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
|
||||
if (length == 0)
|
||||
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
|
||||
buffer_.resize(length + 1);
|
||||
length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size,
|
||||
&buffer_[0], length);
|
||||
length = MultiByteToWideChar(
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
|
||||
if (length == 0)
|
||||
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
|
||||
buffer_[length] = 0;
|
||||
@ -856,8 +885,8 @@ FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
|
||||
|
||||
FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
|
||||
if (int error_code = convert(s)) {
|
||||
FMT_THROW(windows_error(error_code,
|
||||
"cannot convert string from UTF-16 to UTF-8"));
|
||||
FMT_THROW(windows_error(
|
||||
error_code, "cannot convert string from UTF-16 to UTF-8"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -872,21 +901,21 @@ FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0,
|
||||
FMT_NULL, FMT_NULL);
|
||||
int length = WideCharToMultiByte(
|
||||
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
|
||||
if (length == 0)
|
||||
return GetLastError();
|
||||
buffer_.resize(length + 1);
|
||||
length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0],
|
||||
length, FMT_NULL, FMT_NULL);
|
||||
length = WideCharToMultiByte(
|
||||
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
|
||||
if (length == 0)
|
||||
return GetLastError();
|
||||
buffer_[length] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
FMT_FUNC void windows_error::init(int err_code, string_view format_str,
|
||||
format_args args) {
|
||||
FMT_FUNC void windows_error::init(
|
||||
int err_code, string_view format_str, format_args args) {
|
||||
error_code_ = err_code;
|
||||
memory_buffer buffer;
|
||||
internal::format_windows_error(buffer, err_code, vformat(format_str, args));
|
||||
@ -894,18 +923,21 @@ FMT_FUNC void windows_error::init(int err_code, string_view format_str,
|
||||
base = std::runtime_error(to_string(buffer));
|
||||
}
|
||||
|
||||
FMT_FUNC void internal::format_windows_error(internal::buffer &out,
|
||||
int error_code,
|
||||
string_view message) FMT_NOEXCEPT {
|
||||
FMT_FUNC void internal::format_windows_error(
|
||||
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
wmemory_buffer buf;
|
||||
buf.resize(inline_buffer_size);
|
||||
for (;;) {
|
||||
wchar_t *system_message = &buf[0];
|
||||
int result = FormatMessageW(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, FMT_NULL,
|
||||
error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message,
|
||||
static_cast<uint32_t>(buf.size()), FMT_NULL);
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
FMT_NULL,
|
||||
error_code,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
system_message,
|
||||
static_cast<uint32_t>(buf.size()),
|
||||
FMT_NULL);
|
||||
if (result != 0) {
|
||||
utf16_to_utf8 utf8_message;
|
||||
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
|
||||
@ -928,8 +960,8 @@ FMT_FUNC void internal::format_windows_error(internal::buffer &out,
|
||||
|
||||
#endif // FMT_USE_WINDOWS_H
|
||||
|
||||
FMT_FUNC void format_system_error(internal::buffer &out, int error_code,
|
||||
string_view message) FMT_NOEXCEPT {
|
||||
FMT_FUNC void format_system_error(
|
||||
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
memory_buffer buf;
|
||||
buf.resize(inline_buffer_size);
|
||||
@ -956,22 +988,22 @@ FMT_FUNC void internal::error_handler::on_error(const char *message) {
|
||||
FMT_THROW(format_error(message));
|
||||
}
|
||||
|
||||
FMT_FUNC void report_system_error(int error_code,
|
||||
fmt::string_view message) FMT_NOEXCEPT {
|
||||
FMT_FUNC void report_system_error(int error_code, fmt::string_view message)
|
||||
FMT_NOEXCEPT {
|
||||
report_error(format_system_error, error_code, message);
|
||||
}
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
FMT_FUNC void report_windows_error(int error_code,
|
||||
fmt::string_view message) FMT_NOEXCEPT {
|
||||
FMT_FUNC void report_windows_error(int error_code, fmt::string_view message)
|
||||
FMT_NOEXCEPT {
|
||||
report_error(internal::format_windows_error, error_code, message);
|
||||
}
|
||||
#endif
|
||||
|
||||
FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
|
||||
memory_buffer buffer;
|
||||
internal::vformat_to(buffer, format_str,
|
||||
basic_format_args<buffer_context<char>::type>(args));
|
||||
internal::vformat_to(
|
||||
buffer, format_str, basic_format_args<buffer_context<char>::type>(args));
|
||||
std::fwrite(buffer.data(), 1, buffer.size(), f);
|
||||
}
|
||||
|
||||
|
||||
@ -130,8 +130,9 @@ FMT_END_NAMESPACE
|
||||
#ifndef FMT_USE_USER_DEFINED_LITERALS
|
||||
// For Intel's compiler and NVIDIA's compiler both it and the system gcc/msc
|
||||
// must support UDLs.
|
||||
#if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \
|
||||
FMT_MSC_VER >= 1900) && \
|
||||
#if ( \
|
||||
FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \
|
||||
FMT_MSC_VER >= 1900) && \
|
||||
(!(FMT_ICC_VERSION || FMT_CUDA_VERSION) || FMT_ICC_VERSION >= 1500 || \
|
||||
FMT_CUDA_VERSION >= 700)
|
||||
#define FMT_USE_USER_DEFINED_LITERALS 1
|
||||
@ -398,8 +399,8 @@ struct checked {
|
||||
|
||||
// Make a checked iterator to avoid warnings on MSVC.
|
||||
template <typename T>
|
||||
inline stdext::checked_array_iterator<T *> make_checked(T *p,
|
||||
std::size_t size) {
|
||||
inline stdext::checked_array_iterator<T *> make_checked(
|
||||
T *p, std::size_t size) {
|
||||
return {p, size};
|
||||
}
|
||||
#else
|
||||
@ -418,8 +419,8 @@ template <typename U>
|
||||
void basic_buffer<T>::append(const U *begin, const U *end) {
|
||||
std::size_t new_size = size_ + internal::to_unsigned(end - begin);
|
||||
reserve(new_size);
|
||||
std::uninitialized_copy(begin, end,
|
||||
internal::make_checked(ptr_, capacity_) + size_);
|
||||
std::uninitialized_copy(
|
||||
begin, end, internal::make_checked(ptr_, capacity_) + size_);
|
||||
size_ = new_size;
|
||||
}
|
||||
} // namespace internal
|
||||
@ -439,8 +440,8 @@ class u8string_view : public basic_string_view<char8_t> {
|
||||
u8string_view(const char *s)
|
||||
: basic_string_view<char8_t>(reinterpret_cast<const char8_t *>(s)) {}
|
||||
u8string_view(const char *s, size_t count) FMT_NOEXCEPT
|
||||
: basic_string_view<char8_t>(reinterpret_cast<const char8_t *>(s),
|
||||
count) {}
|
||||
: basic_string_view<char8_t>(
|
||||
reinterpret_cast<const char8_t *>(s), count) {}
|
||||
};
|
||||
|
||||
#if FMT_USE_USER_DEFINED_LITERALS
|
||||
@ -484,8 +485,10 @@ enum { inline_buffer_size = 500 };
|
||||
The output can be converted to an ``std::string`` with ``to_string(out)``.
|
||||
\endrst
|
||||
*/
|
||||
template <typename T, std::size_t SIZE = inline_buffer_size,
|
||||
typename Allocator = std::allocator<T>>
|
||||
template <
|
||||
typename T,
|
||||
std::size_t SIZE = inline_buffer_size,
|
||||
typename Allocator = std::allocator<T>>
|
||||
class basic_memory_buffer : private Allocator,
|
||||
public internal::basic_buffer<T> {
|
||||
private:
|
||||
@ -517,8 +520,10 @@ class basic_memory_buffer : private Allocator,
|
||||
std::size_t size = other.size(), capacity = other.capacity();
|
||||
if (data == other.store_) {
|
||||
this->set(store_, capacity);
|
||||
std::uninitialized_copy(other.store_, other.store_ + size,
|
||||
internal::make_checked(store_, capacity));
|
||||
std::uninitialized_copy(
|
||||
other.store_,
|
||||
other.store_ + size,
|
||||
internal::make_checked(store_, capacity));
|
||||
} else {
|
||||
this->set(data, capacity);
|
||||
// Set pointer to the inline array so that delete is not called
|
||||
@ -562,8 +567,10 @@ void basic_memory_buffer<T, SIZE, Allocator>::grow(std::size_t size) {
|
||||
T *old_data = this->data();
|
||||
T *new_data = internal::allocate<Allocator>(*this, new_capacity);
|
||||
// The following code doesn't throw, so the raw pointer above doesn't leak.
|
||||
std::uninitialized_copy(old_data, old_data + this->size(),
|
||||
internal::make_checked(new_data, new_capacity));
|
||||
std::uninitialized_copy(
|
||||
old_data,
|
||||
old_data + this->size(),
|
||||
internal::make_checked(new_data, new_capacity));
|
||||
this->set(new_data, new_capacity);
|
||||
// deallocate must not throw according to the standard, but even if it does,
|
||||
// the buffer already uses the new storage and will deallocate it in
|
||||
@ -584,33 +591,50 @@ template <>
|
||||
struct char_traits<char> {
|
||||
// Formats a floating-point number.
|
||||
template <typename T>
|
||||
FMT_API static int format_float(char *buffer, std::size_t size,
|
||||
const char *format, int precision, T value);
|
||||
FMT_API static int format_float(
|
||||
char *buffer,
|
||||
std::size_t size,
|
||||
const char *format,
|
||||
int precision,
|
||||
T value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct char_traits<wchar_t> {
|
||||
template <typename T>
|
||||
FMT_API static int format_float(wchar_t *buffer, std::size_t size,
|
||||
const wchar_t *format, int precision,
|
||||
T value);
|
||||
FMT_API static int format_float(
|
||||
wchar_t *buffer,
|
||||
std::size_t size,
|
||||
const wchar_t *format,
|
||||
int precision,
|
||||
T value);
|
||||
};
|
||||
|
||||
#if FMT_USE_EXTERN_TEMPLATES
|
||||
extern template int char_traits<char>::format_float<double>(char *buffer,
|
||||
std::size_t size,
|
||||
const char *format,
|
||||
int precision,
|
||||
double value);
|
||||
extern template int char_traits<char>::format_float<double>(
|
||||
char *buffer,
|
||||
std::size_t size,
|
||||
const char *format,
|
||||
int precision,
|
||||
double value);
|
||||
extern template int char_traits<char>::format_float<long double>(
|
||||
char *buffer, std::size_t size, const char *format, int precision,
|
||||
char *buffer,
|
||||
std::size_t size,
|
||||
const char *format,
|
||||
int precision,
|
||||
long double value);
|
||||
|
||||
extern template int char_traits<wchar_t>::format_float<double>(
|
||||
wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
|
||||
wchar_t *buffer,
|
||||
std::size_t size,
|
||||
const wchar_t *format,
|
||||
int precision,
|
||||
double value);
|
||||
extern template int char_traits<wchar_t>::format_float<long double>(
|
||||
wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
|
||||
wchar_t *buffer,
|
||||
std::size_t size,
|
||||
const wchar_t *format,
|
||||
int precision,
|
||||
long double value);
|
||||
#endif
|
||||
|
||||
@ -694,9 +718,10 @@ class truncating_iterator_base {
|
||||
|
||||
// An output iterator that truncates the output and counts the number of objects
|
||||
// written to it.
|
||||
template <typename OutputIt,
|
||||
typename Enable = typename std::is_void<
|
||||
typename std::iterator_traits<OutputIt>::value_type>::type>
|
||||
template <
|
||||
typename OutputIt,
|
||||
typename Enable = typename std::is_void<
|
||||
typename std::iterator_traits<OutputIt>::value_type>::type>
|
||||
class truncating_iterator;
|
||||
|
||||
template <typename OutputIt>
|
||||
@ -768,8 +793,10 @@ template <typename T>
|
||||
struct int_traits {
|
||||
// Smallest of uint32_t and uint64_t that is large enough to represent
|
||||
// all values of T.
|
||||
typedef typename std::conditional<std::numeric_limits<T>::digits <= 32,
|
||||
uint32_t, uint64_t>::type main_type;
|
||||
typedef typename std::conditional<
|
||||
std::numeric_limits<T>::digits <= 32,
|
||||
uint32_t,
|
||||
uint64_t>::type main_type;
|
||||
};
|
||||
|
||||
// Static data is placed in this class template to allow header-only
|
||||
@ -838,21 +865,23 @@ inline char8_t to_char8_t(char c) { return static_cast<char8_t>(c); }
|
||||
template <typename InputIt, typename OutChar>
|
||||
struct needs_conversion
|
||||
: std::integral_constant<
|
||||
bool, std::is_same<typename std::iterator_traits<InputIt>::value_type,
|
||||
char>::value &&
|
||||
std::is_same<OutChar, char8_t>::value> {};
|
||||
bool,
|
||||
std::is_same<
|
||||
typename std::iterator_traits<InputIt>::value_type,
|
||||
char>::value &&
|
||||
std::is_same<OutChar, char8_t>::value> {};
|
||||
|
||||
template <typename OutChar, typename InputIt, typename OutputIt>
|
||||
typename std::enable_if<!needs_conversion<InputIt, OutChar>::value,
|
||||
OutputIt>::type
|
||||
copy_str(InputIt begin, InputIt end, OutputIt it) {
|
||||
typename std::enable_if<!needs_conversion<InputIt, OutChar>::value, OutputIt>::
|
||||
type
|
||||
copy_str(InputIt begin, InputIt end, OutputIt it) {
|
||||
return std::copy(begin, end, it);
|
||||
}
|
||||
|
||||
template <typename OutChar, typename InputIt, typename OutputIt>
|
||||
typename std::enable_if<needs_conversion<InputIt, OutChar>::value,
|
||||
OutputIt>::type
|
||||
copy_str(InputIt begin, InputIt end, OutputIt it) {
|
||||
typename std::enable_if<needs_conversion<InputIt, OutChar>::value, OutputIt>::
|
||||
type
|
||||
copy_str(InputIt begin, InputIt end, OutputIt it) {
|
||||
return std::transform(begin, end, it, to_char8_t);
|
||||
}
|
||||
|
||||
@ -971,8 +1000,10 @@ class add_thousands_sep {
|
||||
if (++digit_index_ % 3 != 0)
|
||||
return;
|
||||
buffer -= sep_.size();
|
||||
std::uninitialized_copy(sep_.data(), sep_.data() + sep_.size(),
|
||||
internal::make_checked(buffer, sep_.size()));
|
||||
std::uninitialized_copy(
|
||||
sep_.data(),
|
||||
sep_.data() + sep_.size(),
|
||||
internal::make_checked(buffer, sep_.size()));
|
||||
}
|
||||
|
||||
enum { size = 1 };
|
||||
@ -995,8 +1026,8 @@ inline wchar_t thousands_sep(locale_ref loc) {
|
||||
// thousands_sep is a functor that is called after writing each char to
|
||||
// add a thousands separator if necessary.
|
||||
template <typename UInt, typename Char, typename ThousandsSep>
|
||||
inline Char *format_decimal(Char *buffer, UInt value, unsigned num_digits,
|
||||
ThousandsSep thousands_sep) {
|
||||
inline Char *format_decimal(
|
||||
Char *buffer, UInt value, unsigned num_digits, ThousandsSep thousands_sep) {
|
||||
buffer += num_digits;
|
||||
Char *end = buffer;
|
||||
while (value >= 100) {
|
||||
@ -1021,10 +1052,13 @@ inline Char *format_decimal(Char *buffer, UInt value, unsigned num_digits,
|
||||
return end;
|
||||
}
|
||||
|
||||
template <typename OutChar, typename UInt, typename Iterator,
|
||||
typename ThousandsSep>
|
||||
inline Iterator format_decimal(Iterator out, UInt value, unsigned num_digits,
|
||||
ThousandsSep sep) {
|
||||
template <
|
||||
typename OutChar,
|
||||
typename UInt,
|
||||
typename Iterator,
|
||||
typename ThousandsSep>
|
||||
inline Iterator format_decimal(
|
||||
Iterator out, UInt value, unsigned num_digits, ThousandsSep sep) {
|
||||
typedef typename ThousandsSep::char_type char_type;
|
||||
// Buffer should be large enough to hold all digits (<= digits10 + 1).
|
||||
enum { max_size = std::numeric_limits<UInt>::digits10 + 1 };
|
||||
@ -1040,8 +1074,8 @@ inline It format_decimal(It out, UInt value, unsigned num_digits) {
|
||||
}
|
||||
|
||||
template <unsigned BASE_BITS, typename Char, typename UInt>
|
||||
inline Char *format_uint(Char *buffer, UInt value, unsigned num_digits,
|
||||
bool upper = false) {
|
||||
inline Char *format_uint(
|
||||
Char *buffer, UInt value, unsigned num_digits, bool upper = false) {
|
||||
buffer += num_digits;
|
||||
Char *end = buffer;
|
||||
do {
|
||||
@ -1053,8 +1087,8 @@ inline Char *format_uint(Char *buffer, UInt value, unsigned num_digits,
|
||||
}
|
||||
|
||||
template <unsigned BASE_BITS, typename Char, typename It, typename UInt>
|
||||
inline It format_uint(It out, UInt value, unsigned num_digits,
|
||||
bool upper = false) {
|
||||
inline It format_uint(
|
||||
It out, UInt value, unsigned num_digits, bool upper = false) {
|
||||
// Buffer should be large enough to hold all digits (digits / BASE_BITS + 1)
|
||||
// and null.
|
||||
char buffer[std::numeric_limits<UInt>::digits / BASE_BITS + 2];
|
||||
@ -1105,8 +1139,10 @@ class utf16_to_utf8 {
|
||||
FMT_API int convert(wstring_view s);
|
||||
};
|
||||
|
||||
FMT_API void format_windows_error(fmt::internal::buffer &out, int error_code,
|
||||
fmt::string_view message) FMT_NOEXCEPT;
|
||||
FMT_API void format_windows_error(
|
||||
fmt::internal::buffer &out,
|
||||
int error_code,
|
||||
fmt::string_view message) FMT_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
template <typename T = void>
|
||||
@ -1232,8 +1268,8 @@ FMT_CONSTEXPR void handle_float_type_spec(char spec, Handler &&handler) {
|
||||
}
|
||||
|
||||
template <typename Char, typename Handler>
|
||||
FMT_CONSTEXPR void handle_char_specs(const basic_format_specs<Char> *specs,
|
||||
Handler &&handler) {
|
||||
FMT_CONSTEXPR void handle_char_specs(
|
||||
const basic_format_specs<Char> *specs, Handler &&handler) {
|
||||
if (!specs)
|
||||
return handler.on_char();
|
||||
if (specs->type && specs->type != 'c')
|
||||
@ -1420,9 +1456,9 @@ class arg_formatter_base {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value ||
|
||||
std::is_same<T, char_type>::value,
|
||||
iterator>::type
|
||||
typename std::enable_if<
|
||||
std::is_integral<T>::value || std::is_same<T, char_type>::value,
|
||||
iterator>::type
|
||||
operator()(T value) {
|
||||
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
||||
// use std::is_same instead.
|
||||
@ -1476,8 +1512,8 @@ class arg_formatter_base {
|
||||
iterator operator()(const char_type *value) {
|
||||
if (!specs_)
|
||||
return write(value), out();
|
||||
internal::handle_cstring_type_spec(specs_->type,
|
||||
cstring_spec_handler(*this, value));
|
||||
internal::handle_cstring_type_spec(
|
||||
specs_->type, cstring_spec_handler(*this, value));
|
||||
return out();
|
||||
}
|
||||
|
||||
@ -1507,9 +1543,8 @@ FMT_CONSTEXPR bool is_name_start(Char c) {
|
||||
// Parses the range [begin, end) as an unsigned integer. This function assumes
|
||||
// that the range is non-empty and the first character is a digit.
|
||||
template <typename Char, typename ErrorHandler>
|
||||
FMT_CONSTEXPR unsigned parse_nonnegative_int(const Char *&begin,
|
||||
const Char *end,
|
||||
ErrorHandler &&eh) {
|
||||
FMT_CONSTEXPR unsigned parse_nonnegative_int(
|
||||
const Char *&begin, const Char *end, ErrorHandler &&eh) {
|
||||
assert(begin != end && '0' <= *begin && *begin <= '9');
|
||||
if (*begin == '0') {
|
||||
++begin;
|
||||
@ -1712,10 +1747,13 @@ class specs_checker : public Handler {
|
||||
internal::type arg_type_;
|
||||
};
|
||||
|
||||
template <template <typename> class Handler, typename T, typename Context,
|
||||
typename ErrorHandler>
|
||||
FMT_CONSTEXPR void set_dynamic_spec(T &value, basic_format_arg<Context> arg,
|
||||
ErrorHandler eh) {
|
||||
template <
|
||||
template <typename> class Handler,
|
||||
typename T,
|
||||
typename Context,
|
||||
typename ErrorHandler>
|
||||
FMT_CONSTEXPR void set_dynamic_spec(
|
||||
T &value, basic_format_arg<Context> arg, ErrorHandler eh) {
|
||||
unsigned long long big_value =
|
||||
visit_format_arg(Handler<ErrorHandler>(eh), arg);
|
||||
if (big_value > to_unsigned((std::numeric_limits<int>::max)()))
|
||||
@ -1731,20 +1769,20 @@ class specs_handler : public specs_setter<typename Context::char_type> {
|
||||
public:
|
||||
typedef typename Context::char_type char_type;
|
||||
|
||||
FMT_CONSTEXPR specs_handler(basic_format_specs<char_type> &specs,
|
||||
Context &ctx)
|
||||
FMT_CONSTEXPR specs_handler(
|
||||
basic_format_specs<char_type> &specs, Context &ctx)
|
||||
: specs_setter<char_type>(specs), context_(ctx) {}
|
||||
|
||||
template <typename Id>
|
||||
FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
|
||||
set_dynamic_spec<width_checker>(this->specs_.width_, get_arg(arg_id),
|
||||
context_.error_handler());
|
||||
set_dynamic_spec<width_checker>(
|
||||
this->specs_.width_, get_arg(arg_id), context_.error_handler());
|
||||
}
|
||||
|
||||
template <typename Id>
|
||||
FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
|
||||
set_dynamic_spec<precision_checker>(this->specs_.precision, get_arg(arg_id),
|
||||
context_.error_handler());
|
||||
set_dynamic_spec<precision_checker>(
|
||||
this->specs_.precision, get_arg(arg_id), context_.error_handler());
|
||||
}
|
||||
|
||||
void on_error(const char *message) { context_.on_error(message); }
|
||||
@ -1804,8 +1842,8 @@ class dynamic_specs_handler
|
||||
public:
|
||||
typedef typename ParseContext::char_type char_type;
|
||||
|
||||
FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs<char_type> &specs,
|
||||
ParseContext &ctx)
|
||||
FMT_CONSTEXPR dynamic_specs_handler(
|
||||
dynamic_format_specs<char_type> &specs, ParseContext &ctx)
|
||||
: specs_setter<char_type>(specs), specs_(specs), context_(ctx) {}
|
||||
|
||||
FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler &other)
|
||||
@ -1845,8 +1883,8 @@ class dynamic_specs_handler
|
||||
};
|
||||
|
||||
template <typename Char, typename IDHandler>
|
||||
FMT_CONSTEXPR const Char *parse_arg_id(const Char *begin, const Char *end,
|
||||
IDHandler &&handler) {
|
||||
FMT_CONSTEXPR const Char *parse_arg_id(
|
||||
const Char *begin, const Char *end, IDHandler &&handler) {
|
||||
assert(begin != end);
|
||||
Char c = *begin;
|
||||
if (c == '}' || c == ':')
|
||||
@ -1908,8 +1946,8 @@ struct precision_adapter {
|
||||
|
||||
// Parses fill and alignment.
|
||||
template <typename Char, typename Handler>
|
||||
FMT_CONSTEXPR const Char *parse_align(const Char *begin, const Char *end,
|
||||
Handler &&handler) {
|
||||
FMT_CONSTEXPR const Char *parse_align(
|
||||
const Char *begin, const Char *end, Handler &&handler) {
|
||||
FMT_ASSERT(begin != end, "");
|
||||
alignment align = ALIGN_DEFAULT;
|
||||
int i = 0;
|
||||
@ -1947,8 +1985,8 @@ FMT_CONSTEXPR const Char *parse_align(const Char *begin, const Char *end,
|
||||
}
|
||||
|
||||
template <typename Char, typename Handler>
|
||||
FMT_CONSTEXPR const Char *parse_width(const Char *begin, const Char *end,
|
||||
Handler &&handler) {
|
||||
FMT_CONSTEXPR const Char *parse_width(
|
||||
const Char *begin, const Char *end, Handler &&handler) {
|
||||
FMT_ASSERT(begin != end, "");
|
||||
if ('0' <= *begin && *begin <= '9') {
|
||||
handler.on_width(parse_nonnegative_int(begin, end, handler));
|
||||
@ -1966,8 +2004,8 @@ FMT_CONSTEXPR const Char *parse_width(const Char *begin, const Char *end,
|
||||
// Parses standard format specifiers and sends notifications about parsed
|
||||
// components to handler.
|
||||
template <typename Char, typename SpecHandler>
|
||||
FMT_CONSTEXPR const Char *parse_format_specs(const Char *begin, const Char *end,
|
||||
SpecHandler &&handler) {
|
||||
FMT_CONSTEXPR const Char *parse_format_specs(
|
||||
const Char *begin, const Char *end, SpecHandler &&handler) {
|
||||
if (begin == end || *begin == '}')
|
||||
return begin;
|
||||
|
||||
@ -2019,8 +2057,8 @@ FMT_CONSTEXPR const Char *parse_format_specs(const Char *begin, const Char *end,
|
||||
} else if (c == '{') {
|
||||
++begin;
|
||||
if (begin != end) {
|
||||
begin = parse_arg_id(begin, end,
|
||||
precision_adapter<SpecHandler, Char>(handler));
|
||||
begin = parse_arg_id(
|
||||
begin, end, precision_adapter<SpecHandler, Char>(handler));
|
||||
}
|
||||
if (begin == end || *begin++ != '}')
|
||||
return handler.on_error("invalid format string"), begin;
|
||||
@ -2047,8 +2085,8 @@ FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr &out) {
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool find<false, char>(const char *first, const char *last, char value,
|
||||
const char *&out) {
|
||||
inline bool find<false, char>(
|
||||
const char *first, const char *last, char value, const char *&out) {
|
||||
out = static_cast<const char *>(std::memchr(first, value, last - first));
|
||||
return out != FMT_NULL;
|
||||
}
|
||||
@ -2067,8 +2105,8 @@ struct id_adapter {
|
||||
};
|
||||
|
||||
template <bool IS_CONSTEXPR, typename Char, typename Handler>
|
||||
FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> format_str,
|
||||
Handler &&handler) {
|
||||
FMT_CONSTEXPR void parse_format_string(
|
||||
basic_string_view<Char> format_str, Handler &&handler) {
|
||||
struct writer {
|
||||
FMT_CONSTEXPR void operator()(const Char *begin, const Char *end) {
|
||||
if (begin == end)
|
||||
@ -2180,8 +2218,8 @@ class format_string_checker {
|
||||
};
|
||||
|
||||
template <typename Char, typename ErrorHandler, typename... Args>
|
||||
FMT_CONSTEXPR bool do_check_format_string(basic_string_view<Char> s,
|
||||
ErrorHandler eh = ErrorHandler()) {
|
||||
FMT_CONSTEXPR bool do_check_format_string(
|
||||
basic_string_view<Char> s, ErrorHandler eh = ErrorHandler()) {
|
||||
format_string_checker<Char, ErrorHandler, Args...> checker(s, eh);
|
||||
parse_format_string<true>(s, checker);
|
||||
return true;
|
||||
@ -2191,9 +2229,9 @@ template <typename... Args, typename S>
|
||||
typename std::enable_if<is_compile_string<S>::value>::type check_format_string(
|
||||
S format_str) {
|
||||
typedef typename S::char_type char_t;
|
||||
FMT_CONSTEXPR_DECL bool invalid_format =
|
||||
internal::do_check_format_string<char_t, internal::error_handler,
|
||||
Args...>(to_string_view(format_str));
|
||||
FMT_CONSTEXPR_DECL bool invalid_format = internal::
|
||||
do_check_format_string<char_t, internal::error_handler, Args...>(
|
||||
to_string_view(format_str));
|
||||
(void)invalid_format;
|
||||
}
|
||||
|
||||
@ -2206,19 +2244,20 @@ struct format_type
|
||||
};
|
||||
|
||||
template <template <typename> class Handler, typename Spec, typename Context>
|
||||
void handle_dynamic_spec(Spec &value, arg_ref<typename Context::char_type> ref,
|
||||
Context &ctx) {
|
||||
void handle_dynamic_spec(
|
||||
Spec &value, arg_ref<typename Context::char_type> ref, Context &ctx) {
|
||||
typedef typename Context::char_type char_type;
|
||||
switch (ref.kind) {
|
||||
case arg_ref<char_type>::NONE:
|
||||
break;
|
||||
case arg_ref<char_type>::INDEX:
|
||||
internal::set_dynamic_spec<Handler>(value, ctx.get_arg(ref.index),
|
||||
ctx.error_handler());
|
||||
internal::set_dynamic_spec<Handler>(
|
||||
value, ctx.get_arg(ref.index), ctx.error_handler());
|
||||
break;
|
||||
case arg_ref<char_type>::NAME:
|
||||
internal::set_dynamic_spec<Handler>(
|
||||
value, ctx.get_arg({ref.name.value, ref.name.size}),
|
||||
value,
|
||||
ctx.get_arg({ref.name.value, ref.name.size}),
|
||||
ctx.error_handler());
|
||||
break;
|
||||
}
|
||||
@ -2323,8 +2362,10 @@ class system_error : public std::runtime_error {
|
||||
may look like "Unknown error -1" and is platform-dependent.
|
||||
\endrst
|
||||
*/
|
||||
FMT_API void format_system_error(internal::buffer &out, int error_code,
|
||||
fmt::string_view message) FMT_NOEXCEPT;
|
||||
FMT_API void format_system_error(
|
||||
internal::buffer &out,
|
||||
int error_code,
|
||||
fmt::string_view message) FMT_NOEXCEPT;
|
||||
|
||||
/**
|
||||
This template provides operations for formatting and writing data into a
|
||||
@ -2398,8 +2439,8 @@ class basic_writer {
|
||||
// <left-padding><prefix><numeric-padding><digits><right-padding>
|
||||
// where <digits> are written by f(it).
|
||||
template <typename Spec, typename F>
|
||||
void write_int(unsigned num_digits, string_view prefix, const Spec &spec,
|
||||
F f) {
|
||||
void write_int(
|
||||
unsigned num_digits, string_view prefix, const Spec &spec, F f) {
|
||||
std::size_t size = prefix.size() + num_digits;
|
||||
char_type fill = static_cast<char_type>(spec.fill());
|
||||
std::size_t padding = 0;
|
||||
@ -2485,8 +2526,8 @@ class basic_writer {
|
||||
|
||||
void on_dec() {
|
||||
unsigned num_digits = internal::count_digits(abs_value);
|
||||
writer.write_int(num_digits, get_prefix(), spec,
|
||||
dec_writer{abs_value, num_digits});
|
||||
writer.write_int(
|
||||
num_digits, get_prefix(), spec, dec_writer{abs_value, num_digits});
|
||||
}
|
||||
|
||||
struct hex_writer {
|
||||
@ -2495,8 +2536,8 @@ class basic_writer {
|
||||
|
||||
template <typename It>
|
||||
void operator()(It &&it) const {
|
||||
it = internal::format_uint<4, char_type>(it, self.abs_value, num_digits,
|
||||
self.spec.type != 'x');
|
||||
it = internal::format_uint<4, char_type>(
|
||||
it, self.abs_value, num_digits, self.spec.type != 'x');
|
||||
}
|
||||
};
|
||||
|
||||
@ -2506,8 +2547,8 @@ class basic_writer {
|
||||
prefix[prefix_size++] = static_cast<char>(spec.type);
|
||||
}
|
||||
unsigned num_digits = count_digits<4>();
|
||||
writer.write_int(num_digits, get_prefix(), spec,
|
||||
hex_writer{*this, num_digits});
|
||||
writer.write_int(
|
||||
num_digits, get_prefix(), spec, hex_writer{*this, num_digits});
|
||||
}
|
||||
|
||||
template <int BITS>
|
||||
@ -2527,8 +2568,8 @@ class basic_writer {
|
||||
prefix[prefix_size++] = static_cast<char>(spec.type);
|
||||
}
|
||||
unsigned num_digits = count_digits<1>();
|
||||
writer.write_int(num_digits, get_prefix(), spec,
|
||||
bin_writer<1>{abs_value, num_digits});
|
||||
writer.write_int(
|
||||
num_digits, get_prefix(), spec, bin_writer<1>{abs_value, num_digits});
|
||||
}
|
||||
|
||||
void on_oct() {
|
||||
@ -2539,8 +2580,8 @@ class basic_writer {
|
||||
// is not greater than the number of digits.
|
||||
prefix[prefix_size++] = '0';
|
||||
}
|
||||
writer.write_int(num_digits, get_prefix(), spec,
|
||||
bin_writer<3>{abs_value, num_digits});
|
||||
writer.write_int(
|
||||
num_digits, get_prefix(), spec, bin_writer<3>{abs_value, num_digits});
|
||||
}
|
||||
|
||||
enum { SEP_SIZE = 1 };
|
||||
@ -2562,8 +2603,8 @@ class basic_writer {
|
||||
unsigned num_digits = internal::count_digits(abs_value);
|
||||
char_type sep = internal::thousands_sep<char_type>(writer.locale_);
|
||||
unsigned size = num_digits + SEP_SIZE * ((num_digits - 1) / 3);
|
||||
writer.write_int(size, get_prefix(), spec,
|
||||
num_writer{abs_value, size, sep});
|
||||
writer.write_int(
|
||||
size, get_prefix(), spec, num_writer{abs_value, size, sep});
|
||||
}
|
||||
|
||||
void on_error() { FMT_THROW(format_error("invalid type specifier")); }
|
||||
@ -2572,8 +2613,8 @@ class basic_writer {
|
||||
// Writes a formatted integer.
|
||||
template <typename T, typename Spec>
|
||||
void write_int(T value, const Spec &spec) {
|
||||
internal::handle_int_type_spec(spec.type,
|
||||
int_writer<T, Spec>(*this, value, spec));
|
||||
internal::handle_int_type_spec(
|
||||
spec.type, int_writer<T, Spec>(*this, value, spec));
|
||||
}
|
||||
|
||||
enum { INF_SIZE = 3 }; // This is an enum to workaround a bug in MSVC.
|
||||
@ -2639,8 +2680,8 @@ class basic_writer {
|
||||
|
||||
public:
|
||||
/** Constructs a ``basic_writer`` object. */
|
||||
explicit basic_writer(Range out,
|
||||
internal::locale_ref loc = internal::locale_ref())
|
||||
explicit basic_writer(
|
||||
Range out, internal::locale_ref loc = internal::locale_ref())
|
||||
: out_(out.begin()), locale_(loc) {}
|
||||
|
||||
iterator out() const { return out_; }
|
||||
@ -2705,8 +2746,8 @@ class basic_writer {
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void write(basic_string_view<Char> s,
|
||||
const format_specs &spec = format_specs()) {
|
||||
void write(
|
||||
basic_string_view<Char> s, const format_specs &spec = format_specs()) {
|
||||
const Char *data = s.data();
|
||||
std::size_t size = s.size();
|
||||
if (spec.precision >= 0 && internal::to_unsigned(spec.precision) < size)
|
||||
@ -2825,8 +2866,8 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
|
||||
|
||||
// Reports a system error without throwing an exception.
|
||||
// Can be used to report errors from destructors.
|
||||
FMT_API void report_system_error(int error_code,
|
||||
string_view message) FMT_NOEXCEPT;
|
||||
FMT_API void report_system_error(int error_code, string_view message)
|
||||
FMT_NOEXCEPT;
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
|
||||
@ -2872,8 +2913,8 @@ class windows_error : public system_error {
|
||||
|
||||
// Reports a Windows error without throwing an exception.
|
||||
// Can be used to report errors from destructors.
|
||||
FMT_API void report_windows_error(int error_code,
|
||||
string_view message) FMT_NOEXCEPT;
|
||||
FMT_API void report_windows_error(int error_code, string_view message)
|
||||
FMT_NOEXCEPT;
|
||||
|
||||
#endif
|
||||
|
||||
@ -2977,16 +3018,19 @@ inline void format_decimal(char *&buffer, T value) {
|
||||
return;
|
||||
}
|
||||
unsigned num_digits = internal::count_digits(abs_value);
|
||||
internal::format_decimal<char>(internal::make_checked(buffer, num_digits),
|
||||
abs_value, num_digits);
|
||||
internal::format_decimal<char>(
|
||||
internal::make_checked(buffer, num_digits), abs_value, num_digits);
|
||||
buffer += num_digits;
|
||||
}
|
||||
|
||||
// Formatter of objects of type T.
|
||||
template <typename T, typename Char>
|
||||
struct formatter<T, Char,
|
||||
typename std::enable_if<internal::format_type<
|
||||
typename buffer_context<Char>::type, T>::value>::type> {
|
||||
struct formatter<
|
||||
T,
|
||||
Char,
|
||||
typename std::enable_if<
|
||||
internal::format_type<typename buffer_context<Char>::type, T>::value>::
|
||||
type> {
|
||||
// Parses format specifiers stopping either at the end of the range or at the
|
||||
// terminating '}'.
|
||||
template <typename ParseContext>
|
||||
@ -2994,8 +3038,8 @@ struct formatter<T, Char,
|
||||
typedef internal::dynamic_specs_handler<ParseContext> handler_type;
|
||||
auto type =
|
||||
internal::get_type<typename buffer_context<Char>::type, T>::value;
|
||||
internal::specs_checker<handler_type> handler(handler_type(specs_, ctx),
|
||||
type);
|
||||
internal::specs_checker<handler_type> handler(
|
||||
handler_type(specs_, ctx), type);
|
||||
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
|
||||
auto type_spec = specs_.type;
|
||||
auto eh = ctx.error_handler();
|
||||
@ -3009,8 +3053,8 @@ struct formatter<T, Char,
|
||||
case internal::long_long_type:
|
||||
case internal::ulong_long_type:
|
||||
case internal::bool_type:
|
||||
handle_int_type_spec(type_spec,
|
||||
internal::int_type_checker<decltype(eh)>(eh));
|
||||
handle_int_type_spec(
|
||||
type_spec, internal::int_type_checker<decltype(eh)>(eh));
|
||||
break;
|
||||
case internal::char_type:
|
||||
handle_char_specs(
|
||||
@ -3018,8 +3062,8 @@ struct formatter<T, Char,
|
||||
break;
|
||||
case internal::double_type:
|
||||
case internal::long_double_type:
|
||||
handle_float_type_spec(type_spec,
|
||||
internal::float_type_checker<decltype(eh)>(eh));
|
||||
handle_float_type_spec(
|
||||
type_spec, internal::float_type_checker<decltype(eh)>(eh));
|
||||
break;
|
||||
case internal::cstring_type:
|
||||
internal::handle_cstring_type_spec(
|
||||
@ -3045,11 +3089,13 @@ struct formatter<T, Char,
|
||||
specs_.width_, specs_.width_ref, ctx);
|
||||
internal::handle_dynamic_spec<internal::precision_checker>(
|
||||
specs_.precision, specs_.precision_ref, ctx);
|
||||
typedef output_range<typename FormatContext::iterator,
|
||||
typename FormatContext::char_type>
|
||||
typedef output_range<
|
||||
typename FormatContext::iterator,
|
||||
typename FormatContext::char_type>
|
||||
range_type;
|
||||
return visit_format_arg(arg_formatter<range_type>(ctx, &specs_),
|
||||
internal::make_arg<FormatContext>(val));
|
||||
return visit_format_arg(
|
||||
arg_formatter<range_type>(ctx, &specs_),
|
||||
internal::make_arg<FormatContext>(val));
|
||||
}
|
||||
|
||||
private:
|
||||
@ -3101,11 +3147,13 @@ class dynamic_formatter {
|
||||
checker.on_hash();
|
||||
if (specs_.precision != -1)
|
||||
checker.end_precision();
|
||||
typedef output_range<typename FormatContext::iterator,
|
||||
typename FormatContext::char_type>
|
||||
typedef output_range<
|
||||
typename FormatContext::iterator,
|
||||
typename FormatContext::char_type>
|
||||
range;
|
||||
visit_format_arg(arg_formatter<range>(ctx, &specs_),
|
||||
internal::make_arg<FormatContext>(val));
|
||||
visit_format_arg(
|
||||
arg_formatter<range>(ctx, &specs_),
|
||||
internal::make_arg<FormatContext>(val));
|
||||
return ctx.out();
|
||||
}
|
||||
|
||||
@ -3135,9 +3183,11 @@ template <typename ArgFormatter, typename Char, typename Context>
|
||||
struct format_handler : internal::error_handler {
|
||||
typedef typename ArgFormatter::range range;
|
||||
|
||||
format_handler(range r, basic_string_view<Char> str,
|
||||
basic_format_args<Context> format_args,
|
||||
internal::locale_ref loc)
|
||||
format_handler(
|
||||
range r,
|
||||
basic_string_view<Char> str,
|
||||
basic_format_args<Context> format_args,
|
||||
internal::locale_ref loc)
|
||||
: context(r.begin(), str, format_args, loc) {}
|
||||
|
||||
void on_text(const Char *begin, const Char *end) {
|
||||
@ -3187,7 +3237,8 @@ struct format_handler : internal::error_handler {
|
||||
/** Formats arguments and writes the output to the range. */
|
||||
template <typename ArgFormatter, typename Char, typename Context>
|
||||
typename Context::iterator vformat_to(
|
||||
typename ArgFormatter::range out, basic_string_view<Char> format_str,
|
||||
typename ArgFormatter::range out,
|
||||
basic_string_view<Char> format_str,
|
||||
basic_format_args<Context> args,
|
||||
internal::locale_ref loc = internal::locale_ref()) {
|
||||
format_handler<ArgFormatter, Char, Context> h(out, format_str, args, loc);
|
||||
@ -3297,30 +3348,36 @@ std::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE> &buf) {
|
||||
|
||||
template <typename Char>
|
||||
typename buffer_context<Char>::type::iterator internal::vformat_to(
|
||||
internal::basic_buffer<Char> &buf, basic_string_view<Char> format_str,
|
||||
internal::basic_buffer<Char> &buf,
|
||||
basic_string_view<Char> format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
typedef back_insert_range<internal::basic_buffer<Char>> range;
|
||||
return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str),
|
||||
args);
|
||||
return vformat_to<arg_formatter<range>>(
|
||||
buf, to_string_view(format_str), args);
|
||||
}
|
||||
|
||||
template <typename S, typename Char = FMT_CHAR(S)>
|
||||
inline typename buffer_context<Char>::type::iterator vformat_to(
|
||||
internal::basic_buffer<Char> &buf, const S &format_str,
|
||||
internal::basic_buffer<Char> &buf,
|
||||
const S &format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
return internal::vformat_to(buf, to_string_view(format_str), args);
|
||||
}
|
||||
|
||||
template <typename S, typename... Args, std::size_t SIZE = inline_buffer_size,
|
||||
typename Char = typename internal::char_t<S>::type>
|
||||
template <
|
||||
typename S,
|
||||
typename... Args,
|
||||
std::size_t SIZE = inline_buffer_size,
|
||||
typename Char = typename internal::char_t<S>::type>
|
||||
inline typename buffer_context<Char>::type::iterator format_to(
|
||||
basic_memory_buffer<Char, SIZE> &buf, const S &format_str,
|
||||
basic_memory_buffer<Char, SIZE> &buf,
|
||||
const S &format_str,
|
||||
const Args &... args) {
|
||||
internal::check_format_string<Args...>(format_str);
|
||||
typedef typename buffer_context<Char>::type context;
|
||||
format_arg_store<context, Args...> as{args...};
|
||||
return internal::vformat_to(buf, to_string_view(format_str),
|
||||
basic_format_args<context>(as));
|
||||
return internal::vformat_to(
|
||||
buf, to_string_view(format_str), basic_format_args<context>(as));
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
@ -3386,13 +3443,15 @@ struct format_args_t {
|
||||
};
|
||||
|
||||
template <typename String, typename OutputIt, typename... Args>
|
||||
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
|
||||
OutputIt>::type
|
||||
vformat_to(OutputIt out, const String &format_str,
|
||||
typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
|
||||
inline typename std::
|
||||
enable_if<internal::is_output_iterator<OutputIt>::value, OutputIt>::type
|
||||
vformat_to(
|
||||
OutputIt out,
|
||||
const String &format_str,
|
||||
typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
|
||||
typedef output_range<OutputIt, FMT_CHAR(String)> range;
|
||||
return vformat_to<arg_formatter<range>>(range(out),
|
||||
to_string_view(format_str), args);
|
||||
return vformat_to<arg_formatter<range>>(
|
||||
range(out), to_string_view(format_str), args);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3407,15 +3466,16 @@ vformat_to(OutputIt out, const String &format_str,
|
||||
\endrst
|
||||
*/
|
||||
template <typename OutputIt, typename S, typename... Args>
|
||||
inline FMT_ENABLE_IF_T(internal::is_string<S>::value
|
||||
&&internal::is_output_iterator<OutputIt>::value,
|
||||
OutputIt)
|
||||
inline FMT_ENABLE_IF_T(
|
||||
internal::is_string<S>::value
|
||||
&&internal::is_output_iterator<OutputIt>::value,
|
||||
OutputIt)
|
||||
format_to(OutputIt out, const S &format_str, const Args &... args) {
|
||||
internal::check_format_string<Args...>(format_str);
|
||||
typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;
|
||||
format_arg_store<context, Args...> as{args...};
|
||||
return vformat_to(out, to_string_view(format_str),
|
||||
basic_format_args<context>(as));
|
||||
return vformat_to(
|
||||
out, to_string_view(format_str), basic_format_args<context>(as));
|
||||
}
|
||||
|
||||
template <typename OutputIt>
|
||||
@ -3437,18 +3497,24 @@ struct format_to_n_args {
|
||||
};
|
||||
|
||||
template <typename OutputIt, typename Char, typename... Args>
|
||||
inline format_arg_store<typename format_to_n_context<OutputIt, Char>::type,
|
||||
Args...>
|
||||
inline format_arg_store<
|
||||
typename format_to_n_context<OutputIt, Char>::type,
|
||||
Args...>
|
||||
make_format_to_n_args(const Args &... args) {
|
||||
return format_arg_store<typename format_to_n_context<OutputIt, Char>::type,
|
||||
Args...>(args...);
|
||||
return format_arg_store<
|
||||
typename format_to_n_context<OutputIt, Char>::type,
|
||||
Args...>(args...);
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename Char, typename... Args>
|
||||
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
|
||||
format_to_n_result<OutputIt>>::type
|
||||
vformat_to_n(OutputIt out, std::size_t n, basic_string_view<Char> format_str,
|
||||
typename format_to_n_args<OutputIt, Char>::type args) {
|
||||
inline typename std::enable_if<
|
||||
internal::is_output_iterator<OutputIt>::value,
|
||||
format_to_n_result<OutputIt>>::type
|
||||
vformat_to_n(
|
||||
OutputIt out,
|
||||
std::size_t n,
|
||||
basic_string_view<Char> format_str,
|
||||
typename format_to_n_args<OutputIt, Char>::type args) {
|
||||
typedef internal::truncating_iterator<OutputIt> It;
|
||||
auto it = vformat_to(It(out, n), format_str, args);
|
||||
return {it.base(), it.count()};
|
||||
@ -3462,17 +3528,24 @@ vformat_to_n(OutputIt out, std::size_t n, basic_string_view<Char> format_str,
|
||||
\endrst
|
||||
*/
|
||||
template <typename OutputIt, typename S, typename... Args>
|
||||
inline FMT_ENABLE_IF_T(internal::is_string<S>::value
|
||||
&&internal::is_output_iterator<OutputIt>::value,
|
||||
format_to_n_result<OutputIt>)
|
||||
format_to_n(OutputIt out, std::size_t n, const S &format_str,
|
||||
const Args &... args) {
|
||||
inline FMT_ENABLE_IF_T(
|
||||
internal::is_string<S>::value
|
||||
&&internal::is_output_iterator<OutputIt>::value,
|
||||
format_to_n_result<OutputIt>)
|
||||
format_to_n(
|
||||
OutputIt out,
|
||||
std::size_t n,
|
||||
const S &format_str,
|
||||
const Args &... args) {
|
||||
internal::check_format_string<Args...>(format_str);
|
||||
typedef FMT_CHAR(S) Char;
|
||||
format_arg_store<typename format_to_n_context<OutputIt, Char>::type, Args...>
|
||||
as(args...);
|
||||
return vformat_to_n(out, n, to_string_view(format_str),
|
||||
typename format_to_n_args<OutputIt, Char>::type(as));
|
||||
return vformat_to_n(
|
||||
out,
|
||||
n,
|
||||
to_string_view(format_str),
|
||||
typename format_to_n_args<OutputIt, Char>::type(as));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
@ -3489,8 +3562,8 @@ inline std::basic_string<Char> internal::vformat(
|
||||
``format(format_str, args...)``.
|
||||
*/
|
||||
template <typename... Args>
|
||||
inline std::size_t formatted_size(string_view format_str,
|
||||
const Args &... args) {
|
||||
inline std::size_t formatted_size(
|
||||
string_view format_str, const Args &... args) {
|
||||
auto it = format_to(internal::counting_iterator<char>(), format_str, args...);
|
||||
return it.count();
|
||||
}
|
||||
@ -3554,12 +3627,12 @@ FMT_CONSTEXPR internal::udl_formatter<Char, CHARS...> operator""_format() {
|
||||
std::string message = "The answer is {}"_format(42);
|
||||
\endrst
|
||||
*/
|
||||
inline internal::udl_formatter<char> operator"" _format(const char *s,
|
||||
std::size_t) {
|
||||
inline internal::udl_formatter<char> operator"" _format(
|
||||
const char *s, std::size_t) {
|
||||
return {s};
|
||||
}
|
||||
inline internal::udl_formatter<wchar_t> operator"" _format(const wchar_t *s,
|
||||
std::size_t) {
|
||||
inline internal::udl_formatter<wchar_t> operator"" _format(
|
||||
const wchar_t *s, std::size_t) {
|
||||
return {s};
|
||||
}
|
||||
#endif // FMT_UDL_TEMPLATE
|
||||
|
||||
@ -17,17 +17,19 @@ FMT_BEGIN_NAMESPACE
|
||||
namespace internal {
|
||||
template <typename Char>
|
||||
typename buffer_context<Char>::type::iterator vformat_to(
|
||||
const std::locale &loc, basic_buffer<Char> &buf,
|
||||
const std::locale &loc,
|
||||
basic_buffer<Char> &buf,
|
||||
basic_string_view<Char> format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
typedef back_insert_range<basic_buffer<Char>> range;
|
||||
return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str), args,
|
||||
internal::locale_ref(loc));
|
||||
return vformat_to<arg_formatter<range>>(
|
||||
buf, to_string_view(format_str), args, internal::locale_ref(loc));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
std::basic_string<Char> vformat(
|
||||
const std::locale &loc, basic_string_view<Char> format_str,
|
||||
const std::locale &loc,
|
||||
basic_string_view<Char> format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
internal::vformat_to(loc, buffer, format_str, args);
|
||||
@ -37,42 +39,49 @@ std::basic_string<Char> vformat(
|
||||
|
||||
template <typename S, typename Char = FMT_CHAR(S)>
|
||||
inline std::basic_string<Char> vformat(
|
||||
const std::locale &loc, const S &format_str,
|
||||
const std::locale &loc,
|
||||
const S &format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
return internal::vformat(loc, to_string_view(format_str), args);
|
||||
}
|
||||
|
||||
template <typename S, typename... Args>
|
||||
inline std::basic_string<FMT_CHAR(S)> format(const std::locale &loc,
|
||||
const S &format_str,
|
||||
const Args &... args) {
|
||||
inline std::basic_string<FMT_CHAR(S)> format(
|
||||
const std::locale &loc, const S &format_str, const Args &... args) {
|
||||
return internal::vformat(
|
||||
loc, to_string_view(format_str),
|
||||
loc,
|
||||
to_string_view(format_str),
|
||||
*internal::checked_args<S, Args...>(format_str, args...));
|
||||
}
|
||||
|
||||
template <typename String, typename OutputIt, typename... Args>
|
||||
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
|
||||
OutputIt>::type
|
||||
vformat_to(OutputIt out, const std::locale &loc, const String &format_str,
|
||||
typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
|
||||
inline typename std::
|
||||
enable_if<internal::is_output_iterator<OutputIt>::value, OutputIt>::type
|
||||
vformat_to(
|
||||
OutputIt out,
|
||||
const std::locale &loc,
|
||||
const String &format_str,
|
||||
typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
|
||||
typedef output_range<OutputIt, FMT_CHAR(String)> range;
|
||||
return vformat_to<arg_formatter<range>>(
|
||||
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args>
|
||||
inline
|
||||
typename std::enable_if<internal::is_string<S>::value &&
|
||||
internal::is_output_iterator<OutputIt>::value,
|
||||
OutputIt>::type
|
||||
format_to(OutputIt out, const std::locale &loc, const S &format_str,
|
||||
const Args &... args) {
|
||||
inline typename std::enable_if<
|
||||
internal::is_string<S>::value &&
|
||||
internal::is_output_iterator<OutputIt>::value,
|
||||
OutputIt>::type
|
||||
format_to(
|
||||
OutputIt out,
|
||||
const std::locale &loc,
|
||||
const S &format_str,
|
||||
const Args &... args) {
|
||||
internal::check_format_string<Args...>(format_str);
|
||||
typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;
|
||||
format_arg_store<context, Args...> as{args...};
|
||||
return vformat_to(out, loc, to_string_view(format_str),
|
||||
basic_format_args<context>(as));
|
||||
return vformat_to(
|
||||
out, loc, to_string_view(format_str), basic_format_args<context>(as));
|
||||
}
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#include "fmt/format.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
for(int i = 0; i < argc; ++i)
|
||||
fmt::print("{}: {}\n", i, argv[i]);
|
||||
for (int i = 0; i < argc; ++i) fmt::print("{}: {}\n", i, argv[i]);
|
||||
}
|
||||
|
||||
@ -9,11 +9,11 @@
|
||||
#include "gtest.h"
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
EXPECT_DEBUG_DEATH(statement, regex)
|
||||
#define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
EXPECT_DEBUG_DEATH(statement, regex)
|
||||
#else
|
||||
# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
|
||||
#define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
|
||||
#endif
|
||||
|
||||
TEST(AssertTest, Fail) {
|
||||
|
||||
@ -34,8 +34,8 @@ std::tm make_second(int s) {
|
||||
return time;
|
||||
}
|
||||
|
||||
std::string format_tm(const std::tm &time, const char *spec,
|
||||
const std::locale &loc) {
|
||||
std::string format_tm(
|
||||
const std::tm &time, const char *spec, const std::locale &loc) {
|
||||
auto &facet = std::use_facet<std::time_put<char>>(loc);
|
||||
std::ostringstream os;
|
||||
os.imbue(loc);
|
||||
@ -43,52 +43,54 @@ std::string format_tm(const std::tm &time, const char *spec,
|
||||
return os.str();
|
||||
}
|
||||
|
||||
#define EXPECT_TIME(spec, time, duration) { \
|
||||
std::locale loc("ja_JP.utf8"); \
|
||||
EXPECT_EQ(format_tm(time, spec, loc), \
|
||||
fmt::format(loc, "{:" spec "}", duration)); \
|
||||
#define EXPECT_TIME(spec, time, duration) \
|
||||
{ \
|
||||
std::locale loc("ja_JP.utf8"); \
|
||||
EXPECT_EQ( \
|
||||
format_tm(time, spec, loc), \
|
||||
fmt::format(loc, "{:" spec "}", duration)); \
|
||||
}
|
||||
|
||||
TEST(ChronoTest, FormatDefault) {
|
||||
EXPECT_EQ("42s", fmt::format("{}", std::chrono::seconds(42)));
|
||||
EXPECT_EQ("42as",
|
||||
fmt::format("{}", std::chrono::duration<int, std::atto>(42)));
|
||||
EXPECT_EQ("42fs",
|
||||
fmt::format("{}", std::chrono::duration<int, std::femto>(42)));
|
||||
EXPECT_EQ("42ps",
|
||||
fmt::format("{}", std::chrono::duration<int, std::pico>(42)));
|
||||
EXPECT_EQ(
|
||||
"42as", fmt::format("{}", std::chrono::duration<int, std::atto>(42)));
|
||||
EXPECT_EQ(
|
||||
"42fs", fmt::format("{}", std::chrono::duration<int, std::femto>(42)));
|
||||
EXPECT_EQ(
|
||||
"42ps", fmt::format("{}", std::chrono::duration<int, std::pico>(42)));
|
||||
EXPECT_EQ("42ns", fmt::format("{}", std::chrono::nanoseconds(42)));
|
||||
EXPECT_EQ("42µs", fmt::format("{}", std::chrono::microseconds(42)));
|
||||
EXPECT_EQ("42ms", fmt::format("{}", std::chrono::milliseconds(42)));
|
||||
EXPECT_EQ("42cs",
|
||||
fmt::format("{}", std::chrono::duration<int, std::centi>(42)));
|
||||
EXPECT_EQ("42ds",
|
||||
fmt::format("{}", std::chrono::duration<int, std::deci>(42)));
|
||||
EXPECT_EQ(
|
||||
"42cs", fmt::format("{}", std::chrono::duration<int, std::centi>(42)));
|
||||
EXPECT_EQ(
|
||||
"42ds", fmt::format("{}", std::chrono::duration<int, std::deci>(42)));
|
||||
EXPECT_EQ("42s", fmt::format("{}", std::chrono::seconds(42)));
|
||||
EXPECT_EQ("42das",
|
||||
fmt::format("{}", std::chrono::duration<int, std::deca>(42)));
|
||||
EXPECT_EQ("42hs",
|
||||
fmt::format("{}", std::chrono::duration<int, std::hecto>(42)));
|
||||
EXPECT_EQ("42ks",
|
||||
fmt::format("{}", std::chrono::duration<int, std::kilo>(42)));
|
||||
EXPECT_EQ("42Ms",
|
||||
fmt::format("{}", std::chrono::duration<int, std::mega>(42)));
|
||||
EXPECT_EQ("42Gs",
|
||||
fmt::format("{}", std::chrono::duration<int, std::giga>(42)));
|
||||
EXPECT_EQ("42Ts",
|
||||
fmt::format("{}", std::chrono::duration<int, std::tera>(42)));
|
||||
EXPECT_EQ("42Ps",
|
||||
fmt::format("{}", std::chrono::duration<int, std::peta>(42)));
|
||||
EXPECT_EQ("42Es",
|
||||
fmt::format("{}", std::chrono::duration<int, std::exa>(42)));
|
||||
EXPECT_EQ(
|
||||
"42das", fmt::format("{}", std::chrono::duration<int, std::deca>(42)));
|
||||
EXPECT_EQ(
|
||||
"42hs", fmt::format("{}", std::chrono::duration<int, std::hecto>(42)));
|
||||
EXPECT_EQ(
|
||||
"42ks", fmt::format("{}", std::chrono::duration<int, std::kilo>(42)));
|
||||
EXPECT_EQ(
|
||||
"42Ms", fmt::format("{}", std::chrono::duration<int, std::mega>(42)));
|
||||
EXPECT_EQ(
|
||||
"42Gs", fmt::format("{}", std::chrono::duration<int, std::giga>(42)));
|
||||
EXPECT_EQ(
|
||||
"42Ts", fmt::format("{}", std::chrono::duration<int, std::tera>(42)));
|
||||
EXPECT_EQ(
|
||||
"42Ps", fmt::format("{}", std::chrono::duration<int, std::peta>(42)));
|
||||
EXPECT_EQ(
|
||||
"42Es", fmt::format("{}", std::chrono::duration<int, std::exa>(42)));
|
||||
EXPECT_EQ("42m", fmt::format("{}", std::chrono::minutes(42)));
|
||||
EXPECT_EQ("42h", fmt::format("{}", std::chrono::hours(42)));
|
||||
EXPECT_EQ("42[15]s",
|
||||
fmt::format("{}",
|
||||
std::chrono::duration<int, std::ratio<15, 1>>(42)));
|
||||
EXPECT_EQ("42[15/4]s",
|
||||
fmt::format("{}",
|
||||
std::chrono::duration<int, std::ratio<15, 4>>(42)));
|
||||
EXPECT_EQ(
|
||||
"42[15]s",
|
||||
fmt::format("{}", std::chrono::duration<int, std::ratio<15, 1>>(42)));
|
||||
EXPECT_EQ(
|
||||
"42[15/4]s",
|
||||
fmt::format("{}", std::chrono::duration<int, std::ratio<15, 4>>(42)));
|
||||
}
|
||||
|
||||
TEST(ChronoTest, Align) {
|
||||
@ -120,8 +122,8 @@ TEST(ChronoTest, FormatSpecs) {
|
||||
EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(24)));
|
||||
EXPECT_EQ("04", fmt::format("{:%I}", std::chrono::hours(4)));
|
||||
EXPECT_EQ("02", fmt::format("{:%I}", std::chrono::hours(14)));
|
||||
EXPECT_EQ("03:25:45",
|
||||
fmt::format("{:%H:%M:%S}", std::chrono::seconds(12345)));
|
||||
EXPECT_EQ(
|
||||
"03:25:45", fmt::format("{:%H:%M:%S}", std::chrono::seconds(12345)));
|
||||
EXPECT_EQ("03:25", fmt::format("{:%R}", std::chrono::seconds(12345)));
|
||||
EXPECT_EQ("03:25:45", fmt::format("{:%T}", std::chrono::seconds(12345)));
|
||||
}
|
||||
@ -144,12 +146,12 @@ TEST(ChronoTest, InvalidSpecs) {
|
||||
EXPECT_THROW_MSG(fmt::format("{:%B}", sec), fmt::format_error, "no date");
|
||||
EXPECT_THROW_MSG(fmt::format("{:%z}", sec), fmt::format_error, "no date");
|
||||
EXPECT_THROW_MSG(fmt::format("{:%Z}", sec), fmt::format_error, "no date");
|
||||
EXPECT_THROW_MSG(fmt::format("{:%q}", sec), fmt::format_error,
|
||||
"invalid format");
|
||||
EXPECT_THROW_MSG(fmt::format("{:%Eq}", sec), fmt::format_error,
|
||||
"invalid format");
|
||||
EXPECT_THROW_MSG(fmt::format("{:%Oq}", sec), fmt::format_error,
|
||||
"invalid format");
|
||||
EXPECT_THROW_MSG(
|
||||
fmt::format("{:%q}", sec), fmt::format_error, "invalid format");
|
||||
EXPECT_THROW_MSG(
|
||||
fmt::format("{:%Eq}", sec), fmt::format_error, "invalid format");
|
||||
EXPECT_THROW_MSG(
|
||||
fmt::format("{:%Oq}", sec), fmt::format_error, "invalid format");
|
||||
}
|
||||
|
||||
TEST(ChronoTest, Locale) {
|
||||
@ -159,7 +161,8 @@ TEST(ChronoTest, Locale) {
|
||||
try {
|
||||
loc = std::locale(loc_name);
|
||||
has_locale = true;
|
||||
} catch (const std::runtime_error &) {}
|
||||
} catch (const std::runtime_error &) {
|
||||
}
|
||||
if (!has_locale) {
|
||||
fmt::print("{} locale is missing.\n", loc_name);
|
||||
return;
|
||||
|
||||
@ -11,9 +11,9 @@
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
|
||||
#include "test-assert.h"
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
// Check if fmt/core.h compiles with windows.h included before it.
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "fmt/core.h"
|
||||
@ -30,9 +30,9 @@
|
||||
#undef max
|
||||
|
||||
using fmt::basic_format_arg;
|
||||
using fmt::string_view;
|
||||
using fmt::internal::basic_buffer;
|
||||
using fmt::internal::value;
|
||||
using fmt::string_view;
|
||||
|
||||
using testing::_;
|
||||
using testing::StrictMock;
|
||||
@ -67,18 +67,18 @@ FMT_END_NAMESPACE
|
||||
|
||||
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
|
||||
TEST(BufferTest, Noncopyable) {
|
||||
EXPECT_FALSE(std::is_copy_constructible<basic_buffer<char> >::value);
|
||||
EXPECT_FALSE(std::is_copy_constructible<basic_buffer<char>>::value);
|
||||
#if !FMT_MSC_VER
|
||||
// std::is_copy_assignable is broken in MSVC2013.
|
||||
EXPECT_FALSE(std::is_copy_assignable<basic_buffer<char> >::value);
|
||||
EXPECT_FALSE(std::is_copy_assignable<basic_buffer<char>>::value);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(BufferTest, Nonmoveable) {
|
||||
EXPECT_FALSE(std::is_move_constructible<basic_buffer<char> >::value);
|
||||
EXPECT_FALSE(std::is_move_constructible<basic_buffer<char>>::value);
|
||||
#if !FMT_MSC_VER
|
||||
// std::is_move_assignable is broken in MSVC2013.
|
||||
EXPECT_FALSE(std::is_move_assignable<basic_buffer<char> >::value);
|
||||
EXPECT_FALSE(std::is_move_assignable<basic_buffer<char>>::value);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@ -91,7 +91,7 @@ struct test_buffer : basic_buffer<T> {
|
||||
|
||||
template <typename T>
|
||||
struct mock_buffer : basic_buffer<T> {
|
||||
MOCK_METHOD1(do_grow, void (std::size_t capacity));
|
||||
MOCK_METHOD1(do_grow, void(std::size_t capacity));
|
||||
|
||||
void grow(std::size_t capacity) {
|
||||
this->set(this->data(), capacity);
|
||||
@ -219,7 +219,7 @@ struct custom_context {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
const char *format(const T &, custom_context& ctx) {
|
||||
const char *format(const T &, custom_context &ctx) {
|
||||
ctx.called = true;
|
||||
return FMT_NULL;
|
||||
}
|
||||
@ -249,7 +249,7 @@ template <typename Char>
|
||||
bool operator==(custom_value<Char> lhs, custom_value<Char> rhs) {
|
||||
return lhs.value == rhs.value;
|
||||
}
|
||||
}
|
||||
} // namespace internal
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
// Use a unique result type to make sure that there are no undesirable
|
||||
@ -259,14 +259,16 @@ struct test_result {};
|
||||
template <typename T>
|
||||
struct mock_visitor {
|
||||
template <typename U>
|
||||
struct result { typedef test_result type; };
|
||||
struct result {
|
||||
typedef test_result type;
|
||||
};
|
||||
|
||||
mock_visitor() {
|
||||
ON_CALL(*this, visit(_)).WillByDefault(testing::Return(test_result()));
|
||||
}
|
||||
|
||||
MOCK_METHOD1_T(visit, test_result (T value));
|
||||
MOCK_METHOD0_T(unexpected, void ());
|
||||
MOCK_METHOD1_T(visit, test_result(T value));
|
||||
MOCK_METHOD0_T(unexpected, void());
|
||||
|
||||
test_result operator()(T value) { return visit(value); }
|
||||
|
||||
@ -278,11 +280,15 @@ struct mock_visitor {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct visit_type { typedef T Type; };
|
||||
struct visit_type {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
#define VISIT_TYPE(Type_, visit_type_) \
|
||||
template <> \
|
||||
struct visit_type<Type_> { typedef visit_type_ Type; }
|
||||
template <> \
|
||||
struct visit_type<Type_> { \
|
||||
typedef visit_type_ Type; \
|
||||
}
|
||||
|
||||
VISIT_TYPE(signed char, int);
|
||||
VISIT_TYPE(unsigned char, unsigned);
|
||||
@ -299,28 +305,42 @@ VISIT_TYPE(unsigned long, unsigned long long);
|
||||
|
||||
VISIT_TYPE(float, double);
|
||||
|
||||
#define CHECK_ARG_(Char, expected, value) { \
|
||||
testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
|
||||
EXPECT_CALL(visitor, visit(expected)); \
|
||||
typedef std::back_insert_iterator<basic_buffer<Char>> iterator; \
|
||||
fmt::visit(visitor, \
|
||||
make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
|
||||
}
|
||||
#define CHECK_ARG_(Char, expected, value) \
|
||||
{ \
|
||||
testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
|
||||
EXPECT_CALL(visitor, visit(expected)); \
|
||||
typedef std::back_insert_iterator<basic_buffer<Char>> iterator; \
|
||||
fmt::visit( \
|
||||
visitor, make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
|
||||
}
|
||||
|
||||
#define CHECK_ARG(value, typename_) { \
|
||||
typedef decltype(value) value_type; \
|
||||
typename_ visit_type<value_type>::Type expected = value; \
|
||||
CHECK_ARG_(char, expected, value) \
|
||||
CHECK_ARG_(wchar_t, expected, value) \
|
||||
}
|
||||
#define CHECK_ARG(value, typename_) \
|
||||
{ \
|
||||
typedef decltype(value) value_type; \
|
||||
typename_ visit_type<value_type>::Type expected = value; \
|
||||
CHECK_ARG_(char, expected, value) \
|
||||
CHECK_ARG_(wchar_t, expected, value) \
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class NumericArgTest : public testing::Test {};
|
||||
|
||||
typedef ::testing::Types<
|
||||
bool, signed char, unsigned char, signed, unsigned short,
|
||||
int, unsigned, long, unsigned long, long long, unsigned long long,
|
||||
float, double, long double> Types;
|
||||
bool,
|
||||
signed char,
|
||||
unsigned char,
|
||||
signed,
|
||||
unsigned short,
|
||||
int,
|
||||
unsigned,
|
||||
long,
|
||||
unsigned long,
|
||||
long long,
|
||||
unsigned long long,
|
||||
float,
|
||||
double,
|
||||
long double>
|
||||
Types;
|
||||
TYPED_TEST_CASE(NumericArgTest, Types);
|
||||
|
||||
template <typename T>
|
||||
@ -330,7 +350,7 @@ typename std::enable_if<std::is_integral<T>::value, T>::type test_value() {
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
||||
test_value() {
|
||||
test_value() {
|
||||
return static_cast<T>(4.2);
|
||||
}
|
||||
|
||||
@ -395,14 +415,14 @@ struct check_custom {
|
||||
TEST(ArgTest, CustomArg) {
|
||||
test_struct test;
|
||||
typedef mock_visitor<fmt::basic_format_arg<fmt::format_context>::handle>
|
||||
visitor;
|
||||
visitor;
|
||||
testing::StrictMock<visitor> v;
|
||||
EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke(check_custom()));
|
||||
fmt::visit(v, make_arg<fmt::format_context>(test));
|
||||
}
|
||||
|
||||
TEST(ArgTest, VisitInvalidArg) {
|
||||
testing::StrictMock< mock_visitor<fmt::monostate> > visitor;
|
||||
testing::StrictMock<mock_visitor<fmt::monostate>> visitor;
|
||||
EXPECT_CALL(visitor, visit(_));
|
||||
fmt::basic_format_arg<fmt::format_context> arg;
|
||||
visit(visitor, arg);
|
||||
@ -461,21 +481,22 @@ template <typename Char>
|
||||
class my_string {
|
||||
public:
|
||||
my_string(const Char *s) : s_(s) {}
|
||||
const Char * data() const FMT_NOEXCEPT { return s_.data(); }
|
||||
const Char *data() const FMT_NOEXCEPT { return s_.data(); }
|
||||
std::size_t length() const FMT_NOEXCEPT { return s_.size(); }
|
||||
operator const Char*() const { return s_.c_str(); }
|
||||
operator const Char *() const { return s_.c_str(); }
|
||||
|
||||
private:
|
||||
std::basic_string<Char> s_;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
inline fmt::basic_string_view<Char>
|
||||
to_string_view(const my_string<Char> &s) FMT_NOEXCEPT {
|
||||
return { s.data(), s.length() };
|
||||
inline fmt::basic_string_view<Char> to_string_view(const my_string<Char> &s)
|
||||
FMT_NOEXCEPT {
|
||||
return {s.data(), s.length()};
|
||||
}
|
||||
|
||||
struct non_string {};
|
||||
}
|
||||
} // namespace my_ns
|
||||
|
||||
namespace FakeQt {
|
||||
class QString {
|
||||
@ -490,12 +511,12 @@ class QString {
|
||||
std::shared_ptr<std::wstring> s_;
|
||||
};
|
||||
|
||||
inline fmt::basic_string_view<wchar_t> to_string_view(
|
||||
const QString &s) FMT_NOEXCEPT {
|
||||
inline fmt::basic_string_view<wchar_t> to_string_view(const QString &s)
|
||||
FMT_NOEXCEPT {
|
||||
return {reinterpret_cast<const wchar_t *>(s.utf16()),
|
||||
static_cast<std::size_t>(s.size())};
|
||||
}
|
||||
}
|
||||
} // namespace FakeQt
|
||||
|
||||
template <typename T>
|
||||
class IsStringTest : public testing::Test {};
|
||||
@ -506,7 +527,7 @@ TYPED_TEST_CASE(IsStringTest, StringCharTypes);
|
||||
namespace {
|
||||
template <typename Char>
|
||||
struct derived_from_string_view : fmt::basic_string_view<Char> {};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TYPED_TEST(IsStringTest, IsString) {
|
||||
EXPECT_TRUE((fmt::internal::is_string<TypeParam *>::value));
|
||||
@ -515,9 +536,9 @@ TYPED_TEST(IsStringTest, IsString) {
|
||||
EXPECT_TRUE((fmt::internal::is_string<const TypeParam[2]>::value));
|
||||
EXPECT_TRUE((fmt::internal::is_string<std::basic_string<TypeParam>>::value));
|
||||
EXPECT_TRUE(
|
||||
(fmt::internal::is_string<fmt::basic_string_view<TypeParam>>::value));
|
||||
(fmt::internal::is_string<fmt::basic_string_view<TypeParam>>::value));
|
||||
EXPECT_TRUE(
|
||||
(fmt::internal::is_string<derived_from_string_view<TypeParam>>::value));
|
||||
(fmt::internal::is_string<derived_from_string_view<TypeParam>>::value));
|
||||
#ifdef FMT_STRING_VIEW
|
||||
EXPECT_TRUE((fmt::internal::is_string<FMT_STRING_VIEW<TypeParam>>::value));
|
||||
#endif
|
||||
@ -529,7 +550,7 @@ TYPED_TEST(IsStringTest, IsString) {
|
||||
TEST(CoreTest, Format) {
|
||||
// This should work without including fmt/format.h.
|
||||
#ifdef FMT_FORMAT_H_
|
||||
# error fmt/format.h must not be included in the core test
|
||||
#error fmt/format.h must not be included in the core test
|
||||
#endif
|
||||
EXPECT_EQ(fmt::format("{}", 42), "42");
|
||||
}
|
||||
@ -537,7 +558,7 @@ TEST(CoreTest, Format) {
|
||||
TEST(CoreTest, FormatTo) {
|
||||
// This should work without including fmt/format.h.
|
||||
#ifdef FMT_FORMAT_H_
|
||||
# error fmt/format.h must not be included in the core test
|
||||
#error fmt/format.h must not be included in the core test
|
||||
#endif
|
||||
std::string s;
|
||||
fmt::format_to(std::back_inserter(s), "{}", 42);
|
||||
@ -595,16 +616,19 @@ struct explicitly_convertible_to_wstring_view {
|
||||
};
|
||||
|
||||
TEST(FormatterTest, FormatExplicitlyConvertibleToWStringView) {
|
||||
EXPECT_EQ(L"foo",
|
||||
fmt::format(L"{}", explicitly_convertible_to_wstring_view()));
|
||||
EXPECT_EQ(
|
||||
L"foo", fmt::format(L"{}", explicitly_convertible_to_wstring_view()));
|
||||
}
|
||||
|
||||
struct explicitly_convertible_to_string_like {
|
||||
template <
|
||||
typename String,
|
||||
typename = typename std::enable_if<
|
||||
std::is_constructible<String, const char*, std::size_t>::value>::type>
|
||||
FMT_EXPLICIT operator String() const { return String("foo", 3u); }
|
||||
std::is_constructible<String, const char *, std::size_t>::value>::
|
||||
type>
|
||||
FMT_EXPLICIT operator String() const {
|
||||
return String("foo", 3u);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(FormatterTest, FormatExplicitlyConvertibleToStringLike) {
|
||||
|
||||
@ -13,15 +13,15 @@
|
||||
|
||||
// A custom argument formatter that doesn't print `-` for floating-point values
|
||||
// rounded to 0.
|
||||
class custom_arg_formatter :
|
||||
public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
|
||||
class custom_arg_formatter
|
||||
: public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
|
||||
public:
|
||||
typedef fmt::back_insert_range<fmt::internal::buffer> range;
|
||||
typedef fmt::arg_formatter<range> base;
|
||||
|
||||
custom_arg_formatter(
|
||||
fmt::format_context &ctx, fmt::format_specs *s = FMT_NULL)
|
||||
: base(ctx, s) {}
|
||||
: base(ctx, s) {}
|
||||
|
||||
using base::operator();
|
||||
|
||||
@ -41,7 +41,7 @@ std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) {
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::string custom_format(const char *format_str, const Args & ... args) {
|
||||
std::string custom_format(const char *format_str, const Args &... args) {
|
||||
auto va = fmt::make_format_args(args...);
|
||||
return custom_vformat(format_str, va);
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#include "fmt/format.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
for(int i = 0; i < argc; ++i)
|
||||
fmt::print("{}: {}\n", i, argv[i]);
|
||||
for (int i = 0; i < argc; ++i) fmt::print("{}: {}\n", i, argv[i]);
|
||||
}
|
||||
|
||||
@ -25,9 +25,9 @@
|
||||
#undef max
|
||||
|
||||
#if FMT_HAS_CPP_ATTRIBUTE(noreturn)
|
||||
# define FMT_NORETURN [[noreturn]]
|
||||
#define FMT_NORETURN [[noreturn]]
|
||||
#else
|
||||
# define FMT_NORETURN
|
||||
#define FMT_NORETURN
|
||||
#endif
|
||||
|
||||
using fmt::internal::fp;
|
||||
@ -108,10 +108,8 @@ TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct ValueExtractor: fmt::internal::function<T> {
|
||||
T operator()(T value) {
|
||||
return value;
|
||||
}
|
||||
struct ValueExtractor : fmt::internal::function<T> {
|
||||
T operator()(T value) { return value; }
|
||||
|
||||
template <typename U>
|
||||
FMT_NORETURN T operator()(U) {
|
||||
@ -122,8 +120,9 @@ struct ValueExtractor: fmt::internal::function<T> {
|
||||
TEST(FormatTest, ArgConverter) {
|
||||
long long value = std::numeric_limits<long long>::max();
|
||||
auto arg = fmt::internal::make_arg<fmt::format_context>(value);
|
||||
visit(fmt::internal::arg_converter<long long, fmt::format_context>(arg, 'd'),
|
||||
arg);
|
||||
visit(
|
||||
fmt::internal::arg_converter<long long, fmt::format_context>(arg, 'd'),
|
||||
arg);
|
||||
EXPECT_EQ(value, visit(ValueExtractor<long long>(), arg));
|
||||
}
|
||||
|
||||
@ -138,10 +137,10 @@ TEST(FormatTest, FormatNegativeNaN) {
|
||||
TEST(FormatTest, StrError) {
|
||||
char *message = FMT_NULL;
|
||||
char buffer[BUFFER_SIZE];
|
||||
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = FMT_NULL, 0),
|
||||
"invalid buffer");
|
||||
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = buffer, 0),
|
||||
"invalid buffer");
|
||||
EXPECT_ASSERT(
|
||||
fmt::safe_strerror(EDOM, message = FMT_NULL, 0), "invalid buffer");
|
||||
EXPECT_ASSERT(
|
||||
fmt::safe_strerror(EDOM, message = buffer, 0), "invalid buffer");
|
||||
buffer[0] = 'x';
|
||||
#if defined(_GNU_SOURCE) && !defined(__COVERITY__)
|
||||
// Use invalid error code to make sure that safe_strerror returns an error
|
||||
@ -188,8 +187,7 @@ TEST(FormatTest, FormatErrorCode) {
|
||||
// Test maximum buffer size.
|
||||
msg = fmt::format("error {}", codes[i]);
|
||||
fmt::memory_buffer buffer;
|
||||
std::string prefix(
|
||||
fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
|
||||
std::string prefix(fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
|
||||
fmt::format_error_code(buffer, codes[i], prefix);
|
||||
EXPECT_EQ(prefix + sep + msg, to_string(buffer));
|
||||
std::size_t size = fmt::inline_buffer_size;
|
||||
@ -207,40 +205,59 @@ TEST(FormatTest, CountCodePoints) {
|
||||
}
|
||||
|
||||
TEST(ColorsTest, Colors) {
|
||||
EXPECT_WRITE(stdout, fmt::print(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"),
|
||||
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
|
||||
EXPECT_WRITE(stdout, fmt::print(fg(fmt::color::blue), "blue"),
|
||||
"\x1b[38;2;000;000;255mblue\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
fmt::print(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"),
|
||||
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
fmt::print(fg(fmt::color::blue), "blue"),
|
||||
"\x1b[38;2;000;000;255mblue\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
fmt::print(fg(fmt::color::blue) | bg(fmt::color::red), "two color"),
|
||||
"\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m");
|
||||
EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::bold, "bold"),
|
||||
"\x1b[1mbold\x1b[0m");
|
||||
EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::italic, "italic"),
|
||||
"\x1b[3mitalic\x1b[0m");
|
||||
EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::underline, "underline"),
|
||||
"\x1b[4munderline\x1b[0m");
|
||||
EXPECT_WRITE(stdout,
|
||||
fmt::print(fmt::emphasis::strikethrough, "strikethrough"),
|
||||
"\x1b[9mstrikethrough\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stdout, fmt::print(fmt::emphasis::bold, "bold"), "\x1b[1mbold\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
fmt::print(fmt::emphasis::italic, "italic"),
|
||||
"\x1b[3mitalic\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
fmt::print(fmt::emphasis::underline, "underline"),
|
||||
"\x1b[4munderline\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
fmt::print(fmt::emphasis::strikethrough, "strikethrough"),
|
||||
"\x1b[9mstrikethrough\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
fmt::print(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"),
|
||||
"\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m");
|
||||
EXPECT_WRITE(stderr, fmt::print(stderr, fmt::emphasis::bold, "bold error"),
|
||||
"\x1b[1mbold error\x1b[0m");
|
||||
EXPECT_WRITE(stderr, fmt::print(stderr, fg(fmt::color::blue), "blue log"),
|
||||
"\x1b[38;2;000;000;255mblue log\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stderr,
|
||||
fmt::print(stderr, fmt::emphasis::bold, "bold error"),
|
||||
"\x1b[1mbold error\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stderr,
|
||||
fmt::print(stderr, fg(fmt::color::blue), "blue log"),
|
||||
"\x1b[38;2;000;000;255mblue log\x1b[0m");
|
||||
EXPECT_WRITE(stdout, fmt::print(fmt::text_style(), "hi"), "hi");
|
||||
EXPECT_WRITE(stdout, fmt::print(fg(fmt::terminal_color::red), "tred"),
|
||||
"\x1b[31mtred\x1b[0m");
|
||||
EXPECT_WRITE(stdout, fmt::print(bg(fmt::terminal_color::cyan), "tcyan"),
|
||||
"\x1b[46mtcyan\x1b[0m");
|
||||
EXPECT_WRITE(stdout,
|
||||
fmt::print(fg(fmt::terminal_color::bright_green), "tbgreen"),
|
||||
"\x1b[92mtbgreen\x1b[0m");
|
||||
EXPECT_WRITE(stdout,
|
||||
fmt::print(bg(fmt::terminal_color::bright_magenta), "tbmagenta"),
|
||||
"\x1b[105mtbmagenta\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
fmt::print(fg(fmt::terminal_color::red), "tred"),
|
||||
"\x1b[31mtred\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
fmt::print(bg(fmt::terminal_color::cyan), "tcyan"),
|
||||
"\x1b[46mtcyan\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
fmt::print(fg(fmt::terminal_color::bright_green), "tbgreen"),
|
||||
"\x1b[92mtbgreen\x1b[0m");
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
fmt::print(bg(fmt::terminal_color::bright_magenta), "tbmagenta"),
|
||||
"\x1b[105mtbmagenta\x1b[0m");
|
||||
}
|
||||
|
||||
1217
test/format-test.cc
1217
test/format-test.cc
File diff suppressed because it is too large
Load Diff
@ -7,14 +7,14 @@
|
||||
|
||||
#include "gtest-extra.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <gtest/gtest-spi.h>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
# include <crtdbg.h> // for _CrtSetReportMode
|
||||
#endif // _WIN32
|
||||
#include <crtdbg.h> // for _CrtSetReportMode
|
||||
#endif // _WIN32
|
||||
|
||||
#include "util.h"
|
||||
|
||||
@ -23,7 +23,7 @@ using testing::internal::scoped_ptr;
|
||||
namespace {
|
||||
|
||||
// This is used to suppress coverity warnings about untrusted values.
|
||||
std::string sanitize(const std::string &s) {
|
||||
std::string sanitize(const std::string& s) {
|
||||
std::string result;
|
||||
for (std::string::const_iterator i = s.begin(), end = s.end(); i != end; ++i)
|
||||
result.push_back(static_cast<char>(*i & 0xff));
|
||||
@ -53,13 +53,9 @@ int SingleEvaluationTest::b_;
|
||||
|
||||
void do_nothing() {}
|
||||
|
||||
void throw_exception() {
|
||||
throw std::runtime_error("test");
|
||||
}
|
||||
void throw_exception() { throw std::runtime_error("test"); }
|
||||
|
||||
void throw_system_error() {
|
||||
throw fmt::system_error(EDOM, "test");
|
||||
}
|
||||
void throw_system_error() { throw fmt::system_error(EDOM, "test"); }
|
||||
|
||||
// Tests that when EXPECT_THROW_MSG fails, it evaluates its message argument
|
||||
// exactly once.
|
||||
@ -88,26 +84,38 @@ TEST_F(SingleEvaluationTest, FailedEXPECT_WRITE) {
|
||||
// Tests that assertion arguments are evaluated exactly once.
|
||||
TEST_F(SingleEvaluationTest, ExceptionTests) {
|
||||
// successful EXPECT_THROW_MSG
|
||||
EXPECT_THROW_MSG({ // NOLINT
|
||||
a_++;
|
||||
throw_exception();
|
||||
}, std::exception, (b_++, "test"));
|
||||
EXPECT_THROW_MSG(
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
throw_exception();
|
||||
},
|
||||
std::exception,
|
||||
(b_++, "test"));
|
||||
EXPECT_EQ(1, a_);
|
||||
EXPECT_EQ(1, b_);
|
||||
|
||||
// failed EXPECT_THROW_MSG, throws different type
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG({ // NOLINT
|
||||
a_++;
|
||||
throw_exception();
|
||||
}, std::logic_error, (b_++, "test")), "throws a different type");
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_THROW_MSG(
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
throw_exception();
|
||||
},
|
||||
std::logic_error,
|
||||
(b_++, "test")),
|
||||
"throws a different type");
|
||||
EXPECT_EQ(2, a_);
|
||||
EXPECT_EQ(2, b_);
|
||||
|
||||
// failed EXPECT_THROW_MSG, throws an exception with different message
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG({ // NOLINT
|
||||
a_++;
|
||||
throw_exception();
|
||||
}, std::exception, (b_++, "other")),
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_THROW_MSG(
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
throw_exception();
|
||||
},
|
||||
std::exception,
|
||||
(b_++, "other")),
|
||||
"throws an exception with a different message");
|
||||
EXPECT_EQ(3, a_);
|
||||
EXPECT_EQ(3, b_);
|
||||
@ -121,26 +129,38 @@ TEST_F(SingleEvaluationTest, ExceptionTests) {
|
||||
|
||||
TEST_F(SingleEvaluationTest, SystemErrorTests) {
|
||||
// successful EXPECT_SYSTEM_ERROR
|
||||
EXPECT_SYSTEM_ERROR({ // NOLINT
|
||||
a_++;
|
||||
throw_system_error();
|
||||
}, EDOM, (b_++, "test"));
|
||||
EXPECT_SYSTEM_ERROR(
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
throw_system_error();
|
||||
},
|
||||
EDOM,
|
||||
(b_++, "test"));
|
||||
EXPECT_EQ(1, a_);
|
||||
EXPECT_EQ(1, b_);
|
||||
|
||||
// failed EXPECT_SYSTEM_ERROR, throws different type
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR({ // NOLINT
|
||||
a_++;
|
||||
throw_exception();
|
||||
}, EDOM, (b_++, "test")), "throws a different type");
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_SYSTEM_ERROR(
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
throw_exception();
|
||||
},
|
||||
EDOM,
|
||||
(b_++, "test")),
|
||||
"throws a different type");
|
||||
EXPECT_EQ(2, a_);
|
||||
EXPECT_EQ(2, b_);
|
||||
|
||||
// failed EXPECT_SYSTEM_ERROR, throws an exception with different message
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR({ // NOLINT
|
||||
a_++;
|
||||
throw_system_error();
|
||||
}, EDOM, (b_++, "other")),
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_SYSTEM_ERROR(
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
throw_system_error();
|
||||
},
|
||||
EDOM,
|
||||
(b_++, "other")),
|
||||
"throws an exception with a different message");
|
||||
EXPECT_EQ(3, a_);
|
||||
EXPECT_EQ(3, b_);
|
||||
@ -155,18 +175,26 @@ TEST_F(SingleEvaluationTest, SystemErrorTests) {
|
||||
// Tests that assertion arguments are evaluated exactly once.
|
||||
TEST_F(SingleEvaluationTest, WriteTests) {
|
||||
// successful EXPECT_WRITE
|
||||
EXPECT_WRITE(stdout, { // NOLINT
|
||||
a_++;
|
||||
std::printf("test");
|
||||
}, (b_++, "test"));
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
std::printf("test");
|
||||
},
|
||||
(b_++, "test"));
|
||||
EXPECT_EQ(1, a_);
|
||||
EXPECT_EQ(1, b_);
|
||||
|
||||
// failed EXPECT_WRITE
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, { // NOLINT
|
||||
a_++;
|
||||
std::printf("test");
|
||||
}, (b_++, "other")), "Actual: test");
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
std::printf("test");
|
||||
},
|
||||
(b_++, "other")),
|
||||
"Actual: test");
|
||||
EXPECT_EQ(2, a_);
|
||||
EXPECT_EQ(2, b_);
|
||||
}
|
||||
@ -179,8 +207,8 @@ TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) {
|
||||
EXPECT_THROW_MSG(throw runtime_error(""), runtime_error, "");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(n++, runtime_error, ""), "");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(throw 1, runtime_error, ""), "");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(
|
||||
throw runtime_error("a"), runtime_error, "b"), "");
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_THROW_MSG(throw runtime_error("a"), runtime_error, "b"), "");
|
||||
}
|
||||
|
||||
// Tests that the compiler will not complain about unreachable code in the
|
||||
@ -190,8 +218,9 @@ TEST(ExpectSystemErrorTest, DoesNotGenerateUnreachableCodeWarning) {
|
||||
EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "test"), EDOM, "test");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(n++, EDOM, ""), "");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw 1, EDOM, ""), "");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
|
||||
throw fmt::system_error(EDOM, "aaa"), EDOM, "bbb"), "");
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "aaa"), EDOM, "bbb"),
|
||||
"");
|
||||
}
|
||||
|
||||
TEST(AssertionSyntaxTest, ExceptionAssertionBehavesLikeSingleStatement) {
|
||||
@ -279,7 +308,8 @@ TEST(StreamingAssertionsTest, EXPECT_THROW_MSG) {
|
||||
<< "unexpected failure";
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_THROW_MSG(throw_exception(), std::exception, "other")
|
||||
<< "expected failure", "expected failure");
|
||||
<< "expected failure",
|
||||
"expected failure");
|
||||
}
|
||||
|
||||
TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) {
|
||||
@ -287,15 +317,15 @@ TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) {
|
||||
<< "unexpected failure";
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other")
|
||||
<< "expected failure", "expected failure");
|
||||
<< "expected failure",
|
||||
"expected failure");
|
||||
}
|
||||
|
||||
TEST(StreamingAssertionsTest, EXPECT_WRITE) {
|
||||
EXPECT_WRITE(stdout, std::printf("test"), "test")
|
||||
<< "unexpected failure";
|
||||
EXPECT_WRITE(stdout, std::printf("test"), "test") << "unexpected failure";
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_WRITE(stdout, std::printf("test"), "other")
|
||||
<< "expected failure", "expected failure");
|
||||
EXPECT_WRITE(stdout, std::printf("test"), "other") << "expected failure",
|
||||
"expected failure");
|
||||
}
|
||||
|
||||
TEST(UtilTest, FormatSystemError) {
|
||||
@ -341,8 +371,8 @@ TEST(OutputRedirectTest, FlushErrorInCtor) {
|
||||
EXPECT_EQ('x', fputc('x', f.get()));
|
||||
FMT_POSIX(close(write_fd));
|
||||
scoped_ptr<OutputRedirect> redir{FMT_NULL};
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
|
||||
EBADF, "cannot flush stream");
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(
|
||||
redir.reset(new OutputRedirect(f.get())), EBADF, "cannot flush stream");
|
||||
redir.reset(FMT_NULL);
|
||||
write_copy.dup2(write_fd); // "undo" close or dtor will fail
|
||||
}
|
||||
@ -353,8 +383,10 @@ TEST(OutputRedirectTest, DupErrorInCtor) {
|
||||
file copy = file::dup(fd);
|
||||
FMT_POSIX(close(fd));
|
||||
scoped_ptr<OutputRedirect> redir{FMT_NULL};
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
|
||||
EBADF, fmt::format("cannot duplicate file descriptor {}", fd));
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(
|
||||
redir.reset(new OutputRedirect(f.get())),
|
||||
EBADF,
|
||||
fmt::format("cannot duplicate file descriptor {}", fd));
|
||||
copy.dup2(fd); // "undo" close or dtor will fail
|
||||
}
|
||||
|
||||
@ -383,8 +415,8 @@ TEST(OutputRedirectTest, FlushErrorInRestoreAndRead) {
|
||||
// Put a character in a file buffer.
|
||||
EXPECT_EQ('x', fputc('x', f.get()));
|
||||
FMT_POSIX(close(write_fd));
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(redir.restore_and_read(),
|
||||
EBADF, "cannot flush stream");
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(
|
||||
redir.restore_and_read(), EBADF, "cannot flush stream");
|
||||
write_copy.dup2(write_fd); // "undo" close or dtor will fail
|
||||
}
|
||||
|
||||
@ -397,15 +429,18 @@ TEST(OutputRedirectTest, ErrorInDtor) {
|
||||
scoped_ptr<OutputRedirect> redir(new OutputRedirect(f.get()));
|
||||
// Put a character in a file buffer.
|
||||
EXPECT_EQ('x', fputc('x', f.get()));
|
||||
EXPECT_WRITE(stderr, {
|
||||
// The close function must be called inside EXPECT_WRITE, otherwise
|
||||
// the system may recycle closed file descriptor when redirecting the
|
||||
// output in EXPECT_STDERR and the second close will break output
|
||||
// redirection.
|
||||
FMT_POSIX(close(write_fd));
|
||||
SUPPRESS_ASSERT(redir.reset(FMT_NULL));
|
||||
}, format_system_error(EBADF, "cannot flush stream"));
|
||||
write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail
|
||||
EXPECT_WRITE(
|
||||
stderr,
|
||||
{
|
||||
// The close function must be called inside EXPECT_WRITE, otherwise
|
||||
// the system may recycle closed file descriptor when redirecting the
|
||||
// output in EXPECT_STDERR and the second close will break output
|
||||
// redirection.
|
||||
FMT_POSIX(close(write_fd));
|
||||
SUPPRESS_ASSERT(redir.reset(FMT_NULL));
|
||||
},
|
||||
format_system_error(EBADF, "cannot flush stream"));
|
||||
write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail
|
||||
}
|
||||
|
||||
#endif // FMT_USE_FILE_DESCRIPTORS
|
||||
|
||||
@ -13,7 +13,7 @@ using fmt::file;
|
||||
|
||||
void OutputRedirect::flush() {
|
||||
#if EOF != -1
|
||||
# error "FMT_RETRY assumes return value of -1 indicating failure"
|
||||
#error "FMT_RETRY assumes return value of -1 indicating failure"
|
||||
#endif
|
||||
int result = 0;
|
||||
FMT_RETRY(result, fflush(file_));
|
||||
|
||||
@ -14,58 +14,59 @@
|
||||
#include "fmt/core.h"
|
||||
|
||||
#ifndef FMT_USE_FILE_DESCRIPTORS
|
||||
# define FMT_USE_FILE_DESCRIPTORS 0
|
||||
#define FMT_USE_FILE_DESCRIPTORS 0
|
||||
#endif
|
||||
|
||||
#if FMT_USE_FILE_DESCRIPTORS
|
||||
# include "fmt/posix.h"
|
||||
#include "fmt/posix.h"
|
||||
#endif
|
||||
|
||||
#define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
|
||||
std::string gtest_expected_message = expected_message; \
|
||||
bool gtest_caught_expected = false; \
|
||||
try { \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
} \
|
||||
catch (expected_exception const& e) { \
|
||||
if (gtest_expected_message != e.what()) { \
|
||||
gtest_ar \
|
||||
<< #statement " throws an exception with a different message.\n" \
|
||||
<< "Expected: " << gtest_expected_message << "\n" \
|
||||
<< " Actual: " << e.what(); \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||
} \
|
||||
gtest_caught_expected = true; \
|
||||
} \
|
||||
catch (...) { \
|
||||
gtest_ar << \
|
||||
"Expected: " #statement " throws an exception of type " \
|
||||
#expected_exception ".\n Actual: it throws a different type."; \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||
} \
|
||||
if (!gtest_caught_expected) { \
|
||||
gtest_ar << \
|
||||
"Expected: " #statement " throws an exception of type " \
|
||||
#expected_exception ".\n Actual: it throws nothing."; \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||
} \
|
||||
} else \
|
||||
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
|
||||
fail(gtest_ar.failure_message())
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
|
||||
std::string gtest_expected_message = expected_message; \
|
||||
bool gtest_caught_expected = false; \
|
||||
try { \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
} catch (expected_exception const &e) { \
|
||||
if (gtest_expected_message != e.what()) { \
|
||||
gtest_ar << #statement \
|
||||
" throws an exception with a different message.\n" \
|
||||
<< "Expected: " << gtest_expected_message << "\n" \
|
||||
<< " Actual: " << e.what(); \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||
} \
|
||||
gtest_caught_expected = true; \
|
||||
} catch (...) { \
|
||||
gtest_ar << "Expected: " #statement \
|
||||
" throws an exception of type " #expected_exception \
|
||||
".\n Actual: it throws a different type."; \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||
} \
|
||||
if (!gtest_caught_expected) { \
|
||||
gtest_ar << "Expected: " #statement \
|
||||
" throws an exception of type " #expected_exception \
|
||||
".\n Actual: it throws nothing."; \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||
} \
|
||||
} else \
|
||||
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
|
||||
: fail(gtest_ar.failure_message())
|
||||
|
||||
// Tests that the statement throws the expected exception and the exception's
|
||||
// what() method returns expected message.
|
||||
#define EXPECT_THROW_MSG(statement, expected_exception, expected_message) \
|
||||
FMT_TEST_THROW_(statement, expected_exception, \
|
||||
expected_message, GTEST_NONFATAL_FAILURE_)
|
||||
FMT_TEST_THROW_( \
|
||||
statement, \
|
||||
expected_exception, \
|
||||
expected_message, \
|
||||
GTEST_NONFATAL_FAILURE_)
|
||||
|
||||
std::string format_system_error(int error_code, fmt::string_view message);
|
||||
|
||||
#define EXPECT_SYSTEM_ERROR(statement, error_code, message) \
|
||||
EXPECT_THROW_MSG(statement, fmt::system_error, \
|
||||
format_system_error(error_code, message))
|
||||
EXPECT_THROW_MSG( \
|
||||
statement, fmt::system_error, format_system_error(error_code, message))
|
||||
|
||||
#if FMT_USE_FILE_DESCRIPTORS
|
||||
|
||||
@ -91,27 +92,26 @@ class OutputRedirect {
|
||||
std::string restore_and_read();
|
||||
};
|
||||
|
||||
#define FMT_TEST_WRITE_(statement, expected_output, file, fail) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
#define FMT_TEST_WRITE_(statement, expected_output, file, fail) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
|
||||
std::string gtest_expected_output = expected_output; \
|
||||
OutputRedirect gtest_redir(file); \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
std::string gtest_output = gtest_redir.restore_and_read(); \
|
||||
if (gtest_output != gtest_expected_output) { \
|
||||
gtest_ar \
|
||||
<< #statement " produces different output.\n" \
|
||||
<< "Expected: " << gtest_expected_output << "\n" \
|
||||
<< " Actual: " << gtest_output; \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||
} \
|
||||
} else \
|
||||
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
|
||||
fail(gtest_ar.failure_message())
|
||||
std::string gtest_expected_output = expected_output; \
|
||||
OutputRedirect gtest_redir(file); \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
std::string gtest_output = gtest_redir.restore_and_read(); \
|
||||
if (gtest_output != gtest_expected_output) { \
|
||||
gtest_ar << #statement " produces different output.\n" \
|
||||
<< "Expected: " << gtest_expected_output << "\n" \
|
||||
<< " Actual: " << gtest_output; \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||
} \
|
||||
} else \
|
||||
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
|
||||
: fail(gtest_ar.failure_message())
|
||||
|
||||
// Tests that the statement writes the expected output to file.
|
||||
#define EXPECT_WRITE(file, statement, expected_output) \
|
||||
FMT_TEST_WRITE_(statement, expected_output, file, GTEST_NONFATAL_FAILURE_)
|
||||
FMT_TEST_WRITE_(statement, expected_output, file, GTEST_NONFATAL_FAILURE_)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
@ -122,23 +122,27 @@ class SuppressAssert {
|
||||
_invalid_parameter_handler original_handler_;
|
||||
int original_report_mode_;
|
||||
|
||||
static void handle_invalid_parameter(const wchar_t *,
|
||||
const wchar_t *, const wchar_t *, unsigned , uintptr_t) {}
|
||||
static void handle_invalid_parameter(
|
||||
const wchar_t *, const wchar_t *, const wchar_t *, unsigned, uintptr_t) {}
|
||||
|
||||
public:
|
||||
SuppressAssert()
|
||||
: original_handler_(_set_invalid_parameter_handler(handle_invalid_parameter)),
|
||||
original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) {
|
||||
}
|
||||
: original_handler_(
|
||||
_set_invalid_parameter_handler(handle_invalid_parameter)),
|
||||
original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) {}
|
||||
~SuppressAssert() {
|
||||
_set_invalid_parameter_handler(original_handler_);
|
||||
_CrtSetReportMode(_CRT_ASSERT, original_report_mode_);
|
||||
}
|
||||
};
|
||||
|
||||
# define SUPPRESS_ASSERT(statement) { SuppressAssert sa; statement; }
|
||||
#define SUPPRESS_ASSERT(statement) \
|
||||
{ \
|
||||
SuppressAssert sa; \
|
||||
statement; \
|
||||
}
|
||||
#else
|
||||
# define SUPPRESS_ASSERT(statement) statement
|
||||
#define SUPPRESS_ASSERT(statement) statement
|
||||
#endif // _MSC_VER
|
||||
|
||||
#define EXPECT_SYSTEM_ERROR_NOASSERT(statement, error_code, message) \
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
#ifndef FMT_MOCK_ALLOCATOR_H_
|
||||
#define FMT_MOCK_ALLOCATOR_H_
|
||||
|
||||
#include "gmock.h"
|
||||
#include "fmt/format.h"
|
||||
#include "gmock.h"
|
||||
|
||||
template <typename T>
|
||||
class mock_allocator {
|
||||
@ -17,8 +17,8 @@ class mock_allocator {
|
||||
mock_allocator() {}
|
||||
mock_allocator(const mock_allocator &) {}
|
||||
typedef T value_type;
|
||||
MOCK_METHOD1_T(allocate, T* (std::size_t n));
|
||||
MOCK_METHOD2_T(deallocate, void (T* p, std::size_t n));
|
||||
MOCK_METHOD1_T(allocate, T *(std::size_t n));
|
||||
MOCK_METHOD2_T(deallocate, void(T *p, std::size_t n));
|
||||
};
|
||||
|
||||
template <typename Allocator>
|
||||
@ -39,13 +39,13 @@ class allocator_ref {
|
||||
allocator_ref(const allocator_ref &other) : alloc_(other.alloc_) {}
|
||||
allocator_ref(allocator_ref &&other) { move(other); }
|
||||
|
||||
allocator_ref& operator=(allocator_ref &&other) {
|
||||
allocator_ref &operator=(allocator_ref &&other) {
|
||||
assert(this != &other);
|
||||
move(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
allocator_ref& operator=(const allocator_ref &other) {
|
||||
allocator_ref &operator=(const allocator_ref &other) {
|
||||
alloc_ = other.alloc_;
|
||||
return *this;
|
||||
}
|
||||
@ -53,10 +53,10 @@ class allocator_ref {
|
||||
public:
|
||||
Allocator *get() const { return alloc_; }
|
||||
|
||||
value_type* allocate(std::size_t n) {
|
||||
value_type *allocate(std::size_t n) {
|
||||
return fmt::internal::allocate(*alloc_, n);
|
||||
}
|
||||
void deallocate(value_type* p, std::size_t n) { alloc_->deallocate(p, n); }
|
||||
void deallocate(value_type *p, std::size_t n) { alloc_->deallocate(p, n); }
|
||||
};
|
||||
|
||||
#endif // FMT_MOCK_ALLOCATOR_H_
|
||||
|
||||
@ -35,7 +35,7 @@ static std::wostream &operator<<(std::wostream &os, TestEnum) {
|
||||
return os << L"TestEnum";
|
||||
}
|
||||
|
||||
enum TestEnum2 {A};
|
||||
enum TestEnum2 { A };
|
||||
|
||||
TEST(OStreamTest, Enum) {
|
||||
EXPECT_FALSE((fmt::convert_to_int<TestEnum, char>::value));
|
||||
@ -48,9 +48,9 @@ TEST(OStreamTest, Enum) {
|
||||
|
||||
typedef fmt::back_insert_range<fmt::internal::buffer> range;
|
||||
|
||||
struct test_arg_formatter: fmt::arg_formatter<range> {
|
||||
struct test_arg_formatter : fmt::arg_formatter<range> {
|
||||
test_arg_formatter(fmt::format_context &ctx, fmt::format_specs &s)
|
||||
: fmt::arg_formatter<range>(ctx, &s) {}
|
||||
: fmt::arg_formatter<range>(ctx, &s) {}
|
||||
};
|
||||
|
||||
TEST(OStreamTest, CustomArg) {
|
||||
@ -68,27 +68,39 @@ TEST(OStreamTest, Format) {
|
||||
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)));
|
||||
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")),
|
||||
format_error, "format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(
|
||||
format("{0:=5}", TestString("def")),
|
||||
format_error,
|
||||
"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()),
|
||||
format_error, "format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0:-}", TestString()),
|
||||
format_error, "format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0: }", TestString()),
|
||||
format_error, "format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0:#}", TestString()),
|
||||
format_error, "format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0:05}", TestString()),
|
||||
format_error, "format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(
|
||||
format("{0:+}", TestString()),
|
||||
format_error,
|
||||
"format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(
|
||||
format("{0:-}", TestString()),
|
||||
format_error,
|
||||
"format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(
|
||||
format("{0: }", TestString()),
|
||||
format_error,
|
||||
"format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(
|
||||
format("{0:#}", TestString()),
|
||||
format_error,
|
||||
"format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(
|
||||
format("{0:05}", TestString()),
|
||||
format_error,
|
||||
"format specifier 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")));
|
||||
@ -134,7 +146,7 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
|
||||
} buffer(max_size);
|
||||
|
||||
struct mock_streambuf : std::streambuf {
|
||||
MOCK_METHOD2(xsputn, std::streamsize (const void *s, std::streamsize n));
|
||||
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);
|
||||
@ -173,11 +185,12 @@ TEST(OStreamTest, ConstexprString) {
|
||||
namespace fmt_test {
|
||||
struct ABC {};
|
||||
|
||||
template <typename Output> Output &operator<<(Output &out, ABC) {
|
||||
template <typename Output>
|
||||
Output &operator<<(Output &out, ABC) {
|
||||
out << "ABC";
|
||||
return out;
|
||||
}
|
||||
} // namespace fmt_test
|
||||
} // namespace fmt_test
|
||||
|
||||
TEST(FormatTest, FormatToN) {
|
||||
char buffer[4];
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
// Disable bogus MSVC warnings.
|
||||
#ifdef _MSC_VER
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "posix-mock.h"
|
||||
@ -18,9 +18,9 @@
|
||||
#include <climits>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <io.h>
|
||||
# undef max
|
||||
# undef ERROR
|
||||
#include <io.h>
|
||||
#undef max
|
||||
#undef ERROR
|
||||
#endif
|
||||
|
||||
#include "gmock.h"
|
||||
@ -31,10 +31,10 @@ using fmt::buffered_file;
|
||||
using fmt::error_code;
|
||||
using fmt::file;
|
||||
|
||||
using testing::internal::scoped_ptr;
|
||||
using testing::_;
|
||||
using testing::StrEq;
|
||||
using testing::Return;
|
||||
using testing::StrEq;
|
||||
using testing::internal::scoped_ptr;
|
||||
|
||||
namespace {
|
||||
int open_count;
|
||||
@ -53,14 +53,14 @@ std::size_t write_nbyte;
|
||||
bool sysconf_error;
|
||||
|
||||
enum FStatSimulation { NONE, MAX_SIZE, ERROR } fstat_sim;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#define EMULATE_EINTR(func, error_result) \
|
||||
if (func##_count != 0) { \
|
||||
if (func##_count++ != 3) { \
|
||||
errno = EINTR; \
|
||||
return error_result; \
|
||||
} \
|
||||
if (func##_count != 0) { \
|
||||
if (func##_count++ != 3) { \
|
||||
errno = EINTR; \
|
||||
return error_result; \
|
||||
} \
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
@ -70,7 +70,7 @@ int test::open(const char *path, int oflag, int mode) {
|
||||
}
|
||||
#else
|
||||
errno_t test::sopen_s(
|
||||
int* pfh, const char *filename, int oflag, int shflag, int pmode) {
|
||||
int *pfh, const char *filename, int oflag, int shflag, int pmode) {
|
||||
EMULATE_EINTR(open, EINTR);
|
||||
return _sopen_s(pfh, filename, oflag, shflag, pmode);
|
||||
}
|
||||
@ -171,7 +171,7 @@ int test::fclose(FILE *stream) {
|
||||
return ::fclose(stream);
|
||||
}
|
||||
|
||||
int (test::fileno)(FILE *stream) {
|
||||
int(test::fileno)(FILE *stream) {
|
||||
EMULATE_EINTR(fileno, -1);
|
||||
#ifdef fileno
|
||||
return FMT_POSIX(fileno(stream));
|
||||
@ -181,18 +181,18 @@ int (test::fileno)(FILE *stream) {
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
# define EXPECT_RETRY(statement, func, message) \
|
||||
func##_count = 1; \
|
||||
statement; \
|
||||
EXPECT_EQ(4, func##_count); \
|
||||
func##_count = 0;
|
||||
# define EXPECT_EQ_POSIX(expected, actual) EXPECT_EQ(expected, actual)
|
||||
#define EXPECT_RETRY(statement, func, message) \
|
||||
func##_count = 1; \
|
||||
statement; \
|
||||
EXPECT_EQ(4, func##_count); \
|
||||
func##_count = 0;
|
||||
#define EXPECT_EQ_POSIX(expected, actual) EXPECT_EQ(expected, actual)
|
||||
#else
|
||||
# define EXPECT_RETRY(statement, func, message) \
|
||||
func##_count = 1; \
|
||||
EXPECT_SYSTEM_ERROR(statement, EINTR, message); \
|
||||
func##_count = 0;
|
||||
# define EXPECT_EQ_POSIX(expected, actual)
|
||||
#define EXPECT_RETRY(statement, func, message) \
|
||||
func##_count = 1; \
|
||||
EXPECT_SYSTEM_ERROR(statement, EINTR, message); \
|
||||
func##_count = 0;
|
||||
#define EXPECT_EQ_POSIX(expected, actual)
|
||||
#endif
|
||||
|
||||
static void write_file(fmt::cstring_view filename, fmt::string_view content) {
|
||||
@ -217,8 +217,8 @@ TEST(UtilTest, GetPageSize) {
|
||||
TEST(FileTest, OpenRetry) {
|
||||
write_file("test", "there must be something here");
|
||||
scoped_ptr<file> f{FMT_NULL};
|
||||
EXPECT_RETRY(f.reset(new file("test", file::RDONLY)),
|
||||
open, "cannot open file test");
|
||||
EXPECT_RETRY(
|
||||
f.reset(new file("test", file::RDONLY)), open, "cannot open file test");
|
||||
#ifndef _WIN32
|
||||
char c = 0;
|
||||
f->read(&c, 1);
|
||||
@ -230,12 +230,15 @@ TEST(FileTest, CloseNoRetryInDtor) {
|
||||
file::pipe(read_end, write_end);
|
||||
scoped_ptr<file> f(new file(std::move(read_end)));
|
||||
int saved_close_count = 0;
|
||||
EXPECT_WRITE(stderr, {
|
||||
close_count = 1;
|
||||
f.reset(FMT_NULL);
|
||||
saved_close_count = close_count;
|
||||
close_count = 0;
|
||||
}, format_system_error(EINTR, "cannot close file") + "\n");
|
||||
EXPECT_WRITE(
|
||||
stderr,
|
||||
{
|
||||
close_count = 1;
|
||||
f.reset(FMT_NULL);
|
||||
saved_close_count = close_count;
|
||||
close_count = 0;
|
||||
},
|
||||
format_system_error(EINTR, "cannot close file") + "\n");
|
||||
EXPECT_EQ(2, saved_close_count);
|
||||
}
|
||||
|
||||
@ -284,8 +287,8 @@ TEST(FileTest, ReadRetry) {
|
||||
write_end.close();
|
||||
char buffer[SIZE];
|
||||
std::size_t count = 0;
|
||||
EXPECT_RETRY(count = read_end.read(buffer, SIZE),
|
||||
read, "cannot read from file");
|
||||
EXPECT_RETRY(
|
||||
count = read_end.read(buffer, SIZE), read, "cannot read from file");
|
||||
EXPECT_EQ_POSIX(static_cast<std::streamsize>(SIZE), count);
|
||||
}
|
||||
|
||||
@ -294,8 +297,8 @@ TEST(FileTest, WriteRetry) {
|
||||
file::pipe(read_end, write_end);
|
||||
enum { SIZE = 4 };
|
||||
std::size_t count = 0;
|
||||
EXPECT_RETRY(count = write_end.write("test", SIZE),
|
||||
write, "cannot write to file");
|
||||
EXPECT_RETRY(
|
||||
count = write_end.write("test", SIZE), write, "cannot write to file");
|
||||
write_end.close();
|
||||
#ifndef _WIN32
|
||||
EXPECT_EQ(static_cast<std::streamsize>(SIZE), count);
|
||||
@ -339,7 +342,9 @@ TEST(FileTest, ConvertWriteCount) {
|
||||
TEST(FileTest, DupNoRetry) {
|
||||
int stdout_fd = FMT_POSIX(fileno(stdout));
|
||||
dup_count = 1;
|
||||
EXPECT_SYSTEM_ERROR(file::dup(stdout_fd), EINTR,
|
||||
EXPECT_SYSTEM_ERROR(
|
||||
file::dup(stdout_fd),
|
||||
EINTR,
|
||||
fmt::format("cannot duplicate file descriptor {}", stdout_fd));
|
||||
dup_count = 0;
|
||||
}
|
||||
@ -347,9 +352,13 @@ TEST(FileTest, DupNoRetry) {
|
||||
TEST(FileTest, Dup2Retry) {
|
||||
int stdout_fd = FMT_POSIX(fileno(stdout));
|
||||
file f1 = file::dup(stdout_fd), f2 = file::dup(stdout_fd);
|
||||
EXPECT_RETRY(f1.dup2(f2.descriptor()), dup2,
|
||||
fmt::format("cannot duplicate file descriptor {} to {}",
|
||||
f1.descriptor(), f2.descriptor()));
|
||||
EXPECT_RETRY(
|
||||
f1.dup2(f2.descriptor()),
|
||||
dup2,
|
||||
fmt::format(
|
||||
"cannot duplicate file descriptor {} to {}",
|
||||
f1.descriptor(),
|
||||
f2.descriptor()));
|
||||
}
|
||||
|
||||
TEST(FileTest, Dup2NoExceptRetry) {
|
||||
@ -378,16 +387,18 @@ TEST(FileTest, FdopenNoRetry) {
|
||||
file read_end, write_end;
|
||||
file::pipe(read_end, write_end);
|
||||
fdopen_count = 1;
|
||||
EXPECT_SYSTEM_ERROR(read_end.fdopen("r"),
|
||||
EINTR, "cannot associate stream with file descriptor");
|
||||
EXPECT_SYSTEM_ERROR(
|
||||
read_end.fdopen("r"),
|
||||
EINTR,
|
||||
"cannot associate stream with file descriptor");
|
||||
fdopen_count = 0;
|
||||
}
|
||||
|
||||
TEST(BufferedFileTest, OpenRetry) {
|
||||
write_file("test", "there must be something here");
|
||||
scoped_ptr<buffered_file> f{FMT_NULL};
|
||||
EXPECT_RETRY(f.reset(new buffered_file("test", "r")),
|
||||
fopen, "cannot open file test");
|
||||
EXPECT_RETRY(
|
||||
f.reset(new buffered_file("test", "r")), fopen, "cannot open file test");
|
||||
#ifndef _WIN32
|
||||
char c = 0;
|
||||
if (fread(&c, 1, 1, f->get()) < 1)
|
||||
@ -400,12 +411,15 @@ TEST(BufferedFileTest, CloseNoRetryInDtor) {
|
||||
file::pipe(read_end, write_end);
|
||||
scoped_ptr<buffered_file> f(new buffered_file(read_end.fdopen("r")));
|
||||
int saved_fclose_count = 0;
|
||||
EXPECT_WRITE(stderr, {
|
||||
fclose_count = 1;
|
||||
f.reset(FMT_NULL);
|
||||
saved_fclose_count = fclose_count;
|
||||
fclose_count = 0;
|
||||
}, format_system_error(EINTR, "cannot close file") + "\n");
|
||||
EXPECT_WRITE(
|
||||
stderr,
|
||||
{
|
||||
fclose_count = 1;
|
||||
f.reset(FMT_NULL);
|
||||
saved_fclose_count = fclose_count;
|
||||
fclose_count = 0;
|
||||
},
|
||||
format_system_error(EINTR, "cannot close file") + "\n");
|
||||
EXPECT_EQ(2, saved_fclose_count);
|
||||
}
|
||||
|
||||
@ -431,7 +445,7 @@ TEST(BufferedFileTest, FilenoNoRetry) {
|
||||
|
||||
struct TestMock {
|
||||
static TestMock *instance;
|
||||
} *TestMock::instance;
|
||||
} * TestMock::instance;
|
||||
|
||||
TEST(ScopedMock, Scope) {
|
||||
{
|
||||
@ -449,17 +463,18 @@ typedef fmt::Locale::Type LocaleType;
|
||||
|
||||
struct LocaleMock {
|
||||
static LocaleMock *instance;
|
||||
MOCK_METHOD3(newlocale, LocaleType (int category_mask, const char *locale,
|
||||
LocaleType base));
|
||||
MOCK_METHOD1(freelocale, void (LocaleType locale));
|
||||
MOCK_METHOD3(
|
||||
newlocale,
|
||||
LocaleType(int category_mask, const char *locale, LocaleType base));
|
||||
MOCK_METHOD1(freelocale, void(LocaleType locale));
|
||||
|
||||
MOCK_METHOD3(strtod_l, double (const char *nptr, char **endptr,
|
||||
LocaleType locale));
|
||||
} *LocaleMock::instance;
|
||||
MOCK_METHOD3(
|
||||
strtod_l, double(const char *nptr, char **endptr, LocaleType locale));
|
||||
} * LocaleMock::instance;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4273)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4273)
|
||||
|
||||
_locale_t _create_locale(int category, const char *locale) {
|
||||
return LocaleMock::instance->newlocale(category, locale, 0);
|
||||
@ -472,7 +487,7 @@ void _free_locale(_locale_t locale) {
|
||||
double _strtod_l(const char *nptr, char **endptr, _locale_t locale) {
|
||||
return LocaleMock::instance->strtod_l(nptr, endptr, locale);
|
||||
}
|
||||
# pragma warning(pop)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#if defined(__THROW) && FMT_GCC_VERSION > 0 && FMT_GCC_VERSION <= 408
|
||||
@ -481,7 +496,8 @@ double _strtod_l(const char *nptr, char **endptr, _locale_t locale) {
|
||||
#define FMT_LOCALE_THROW
|
||||
#endif
|
||||
|
||||
LocaleType newlocale(int category_mask, const char *locale, LocaleType base) FMT_LOCALE_THROW {
|
||||
LocaleType newlocale(int category_mask, const char *locale, LocaleType base)
|
||||
FMT_LOCALE_THROW {
|
||||
return LocaleMock::instance->newlocale(category_mask, locale, base);
|
||||
}
|
||||
|
||||
@ -496,7 +512,8 @@ FreeLocaleResult freelocale(LocaleType locale) FMT_LOCALE_THROW {
|
||||
return FreeLocaleResult();
|
||||
}
|
||||
|
||||
double strtod_l(const char *nptr, char **endptr, LocaleType locale) FMT_LOCALE_THROW {
|
||||
double strtod_l(const char *nptr, char **endptr, LocaleType locale)
|
||||
FMT_LOCALE_THROW {
|
||||
return LocaleMock::instance->strtod_l(nptr, endptr, locale);
|
||||
}
|
||||
|
||||
|
||||
@ -12,10 +12,10 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
# include <sys/param.h> // for FreeBSD version
|
||||
# include <sys/types.h> // for ssize_t
|
||||
#include <sys/param.h> // for FreeBSD version
|
||||
#include <sys/types.h> // for ssize_t
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
@ -34,7 +34,7 @@ int fstat(int fd, struct stat *buf);
|
||||
typedef unsigned size_t;
|
||||
typedef int ssize_t;
|
||||
errno_t sopen_s(
|
||||
int* pfh, const char *filename, int oflag, int shflag, int pmode);
|
||||
int *pfh, const char *filename, int oflag, int shflag, int pmode);
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
@ -61,7 +61,7 @@ int pipe(int *pfds, unsigned psize, int textmode);
|
||||
|
||||
FILE *fopen(const char *filename, const char *mode);
|
||||
int fclose(FILE *stream);
|
||||
int (fileno)(FILE *stream);
|
||||
int(fileno)(FILE *stream);
|
||||
} // namespace test
|
||||
|
||||
#define FMT_SYSTEM(call) test::call
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
#include "util.h"
|
||||
|
||||
#ifdef fileno
|
||||
# undef fileno
|
||||
#undef fileno
|
||||
#endif
|
||||
|
||||
using fmt::buffered_file;
|
||||
@ -120,14 +120,17 @@ TEST(BufferedFileTest, CloseFileInDtor) {
|
||||
|
||||
TEST(BufferedFileTest, CloseErrorInDtor) {
|
||||
scoped_ptr<buffered_file> f(new buffered_file(open_buffered_file()));
|
||||
EXPECT_WRITE(stderr, {
|
||||
// The close function must be called inside EXPECT_WRITE, otherwise
|
||||
// the system may recycle closed file descriptor when redirecting the
|
||||
// output in EXPECT_STDERR and the second close will break output
|
||||
// redirection.
|
||||
FMT_POSIX(close(f->fileno()));
|
||||
SUPPRESS_ASSERT(f.reset(FMT_NULL));
|
||||
}, format_system_error(EBADF, "cannot close file") + "\n");
|
||||
EXPECT_WRITE(
|
||||
stderr,
|
||||
{
|
||||
// The close function must be called inside EXPECT_WRITE, otherwise
|
||||
// the system may recycle closed file descriptor when redirecting the
|
||||
// output in EXPECT_STDERR and the second close will break output
|
||||
// redirection.
|
||||
FMT_POSIX(close(f->fileno()));
|
||||
SUPPRESS_ASSERT(f.reset(FMT_NULL));
|
||||
},
|
||||
format_system_error(EBADF, "cannot close file") + "\n");
|
||||
}
|
||||
|
||||
TEST(BufferedFileTest, Close) {
|
||||
@ -150,13 +153,15 @@ TEST(BufferedFileTest, Fileno) {
|
||||
#ifndef __COVERITY__
|
||||
// fileno on a null FILE pointer either crashes or returns an error.
|
||||
// Disable Coverity because this is intentional.
|
||||
EXPECT_DEATH_IF_SUPPORTED({
|
||||
try {
|
||||
f.fileno();
|
||||
} catch (const fmt::system_error&) {
|
||||
std::exit(1);
|
||||
}
|
||||
}, "");
|
||||
EXPECT_DEATH_IF_SUPPORTED(
|
||||
{
|
||||
try {
|
||||
f.fileno();
|
||||
} catch (const fmt::system_error &) {
|
||||
std::exit(1);
|
||||
}
|
||||
},
|
||||
"");
|
||||
#endif
|
||||
f = open_buffered_file();
|
||||
EXPECT_TRUE(f.fileno() != -1);
|
||||
@ -178,8 +183,10 @@ TEST(FileTest, OpenBufferedFileInCtor) {
|
||||
}
|
||||
|
||||
TEST(FileTest, OpenBufferedFileError) {
|
||||
EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY),
|
||||
ENOENT, "cannot open file nonexistent");
|
||||
EXPECT_SYSTEM_ERROR(
|
||||
file("nonexistent", file::RDONLY),
|
||||
ENOENT,
|
||||
"cannot open file nonexistent");
|
||||
}
|
||||
|
||||
TEST(FileTest, MoveCtor) {
|
||||
@ -247,14 +254,17 @@ TEST(FileTest, CloseFileInDtor) {
|
||||
|
||||
TEST(FileTest, CloseErrorInDtor) {
|
||||
scoped_ptr<file> f(new file(open_file()));
|
||||
EXPECT_WRITE(stderr, {
|
||||
// The close function must be called inside EXPECT_WRITE, otherwise
|
||||
// the system may recycle closed file descriptor when redirecting the
|
||||
// output in EXPECT_STDERR and the second close will break output
|
||||
// redirection.
|
||||
FMT_POSIX(close(f->descriptor()));
|
||||
SUPPRESS_ASSERT(f.reset(FMT_NULL));
|
||||
}, format_system_error(EBADF, "cannot close file") + "\n");
|
||||
EXPECT_WRITE(
|
||||
stderr,
|
||||
{
|
||||
// The close function must be called inside EXPECT_WRITE, otherwise
|
||||
// the system may recycle closed file descriptor when redirecting the
|
||||
// output in EXPECT_STDERR and the second close will break output
|
||||
// redirection.
|
||||
FMT_POSIX(close(f->descriptor()));
|
||||
SUPPRESS_ASSERT(f.reset(FMT_NULL));
|
||||
},
|
||||
format_system_error(EBADF, "cannot close file") + "\n");
|
||||
}
|
||||
|
||||
TEST(FileTest, Close) {
|
||||
@ -310,8 +320,8 @@ TEST(FileTest, Dup) {
|
||||
#ifndef __COVERITY__
|
||||
TEST(FileTest, DupError) {
|
||||
int value = -1;
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value),
|
||||
EBADF, "cannot duplicate file descriptor -1");
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(
|
||||
file::dup(value), EBADF, "cannot duplicate file descriptor -1");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -325,8 +335,10 @@ TEST(FileTest, Dup2) {
|
||||
|
||||
TEST(FileTest, Dup2Error) {
|
||||
file f = open_file();
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(f.dup2(-1), EBADF,
|
||||
fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor()));
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(
|
||||
f.dup2(-1),
|
||||
EBADF,
|
||||
fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor()));
|
||||
}
|
||||
|
||||
TEST(FileTest, Dup2NoExcept) {
|
||||
|
||||
@ -43,9 +43,9 @@ std::wstring test_sprintf(fmt::wstring_view format, const Args &... args) {
|
||||
return fmt::sprintf(format, args...);
|
||||
}
|
||||
|
||||
#define EXPECT_PRINTF(expected_output, format, arg) \
|
||||
#define EXPECT_PRINTF(expected_output, format, arg) \
|
||||
EXPECT_EQ(expected_output, test_sprintf(format, arg)) \
|
||||
<< "format: " << format; \
|
||||
<< "format: " << format; \
|
||||
EXPECT_EQ(expected_output, fmt::sprintf(make_positional(format), arg))
|
||||
|
||||
TEST(PrintfTest, NoArgs) {
|
||||
@ -69,11 +69,10 @@ TEST(PrintfTest, Escape) {
|
||||
TEST(PrintfTest, PositionalArgs) {
|
||||
EXPECT_EQ("42", test_sprintf("%1$d", 42));
|
||||
EXPECT_EQ("before 42", test_sprintf("before %1$d", 42));
|
||||
EXPECT_EQ("42 after", test_sprintf("%1$d after",42));
|
||||
EXPECT_EQ("42 after", test_sprintf("%1$d after", 42));
|
||||
EXPECT_EQ("before 42 after", test_sprintf("before %1$d after", 42));
|
||||
EXPECT_EQ("answer = 42", test_sprintf("%1$s = %2$d", "answer", 42));
|
||||
EXPECT_EQ("42 is the answer",
|
||||
test_sprintf("%2$d is the %1$s", "answer", 42));
|
||||
EXPECT_EQ("42 is the answer", test_sprintf("%2$d is the %1$s", "answer", 42));
|
||||
EXPECT_EQ("abracadabra", test_sprintf("%1$s%2$s%1$s", "abra", "cad"));
|
||||
}
|
||||
|
||||
@ -82,46 +81,68 @@ TEST(PrintfTest, AutomaticArgIndexing) {
|
||||
}
|
||||
|
||||
TEST(PrintfTest, NumberIsTooBigInArgIndex) {
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$", BIG_NUM)),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM)),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf(format("%{}$", BIG_NUM)), format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf(format("%{}$d", BIG_NUM)),
|
||||
format_error,
|
||||
"number is too big");
|
||||
}
|
||||
|
||||
TEST(PrintfTest, SwitchArgIndexing) {
|
||||
EXPECT_THROW_MSG(test_sprintf("%1$d%", 1, 2),
|
||||
format_error, "cannot switch from manual to automatic argument indexing");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf("%1$d%d", 1, 2),
|
||||
format_error, "cannot switch from manual to automatic argument indexing");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%1$d%", 1, 2),
|
||||
format_error,
|
||||
"cannot switch from manual to automatic argument indexing");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
|
||||
format_error,
|
||||
"number is too big");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%1$d%d", 1, 2),
|
||||
format_error,
|
||||
"cannot switch from manual to automatic argument indexing");
|
||||
|
||||
EXPECT_THROW_MSG(test_sprintf("%d%1$", 1, 2),
|
||||
format_error, "cannot switch from automatic to manual argument indexing");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%d%{}$d", BIG_NUM), 1, 2),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf("%d%1$d", 1, 2),
|
||||
format_error, "cannot switch from automatic to manual argument indexing");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%d%1$", 1, 2),
|
||||
format_error,
|
||||
"cannot switch from automatic to manual argument indexing");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf(format("%d%{}$d", BIG_NUM), 1, 2),
|
||||
format_error,
|
||||
"number is too big");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%d%1$d", 1, 2),
|
||||
format_error,
|
||||
"cannot switch from automatic to manual argument indexing");
|
||||
|
||||
// Indexing errors override width errors.
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%d%1${}d", BIG_NUM), 1, 2),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf(format("%d%1${}d", BIG_NUM), 1, 2),
|
||||
format_error,
|
||||
"number is too big");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
|
||||
format_error,
|
||||
"number is too big");
|
||||
}
|
||||
|
||||
TEST(PrintfTest, InvalidArgIndex) {
|
||||
EXPECT_THROW_MSG(test_sprintf("%0$d", 42), format_error,
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%0$d", 42), format_error, "argument index out of range");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%2$d", 42), format_error, "argument index out of range");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf(format("%{}$d", INT_MAX), 42),
|
||||
format_error,
|
||||
"argument index out of range");
|
||||
EXPECT_THROW_MSG(test_sprintf("%2$d", 42), format_error,
|
||||
"argument index out of range");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", INT_MAX), 42),
|
||||
format_error, "argument index out of range");
|
||||
|
||||
EXPECT_THROW_MSG(test_sprintf("%2$", 42),
|
||||
format_error, "argument index out of range");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM), 42),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%2$", 42), format_error, "argument index out of range");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf(format("%{}$d", BIG_NUM), 42),
|
||||
format_error,
|
||||
"number is too big");
|
||||
}
|
||||
|
||||
TEST(PrintfTest, DefaultAlignRight) {
|
||||
@ -176,7 +197,7 @@ TEST(PrintfTest, HashFlag) {
|
||||
EXPECT_PRINTF("0x42", "%#x", 0x42);
|
||||
EXPECT_PRINTF("0X42", "%#X", 0x42);
|
||||
EXPECT_PRINTF(
|
||||
fmt::format("0x{:x}", static_cast<unsigned>(-0x42)), "%#x", -0x42);
|
||||
fmt::format("0x{:x}", static_cast<unsigned>(-0x42)), "%#x", -0x42);
|
||||
EXPECT_PRINTF("0", "%#x", 0);
|
||||
|
||||
EXPECT_PRINTF("0x0042", "%#06x", 0x42);
|
||||
@ -207,24 +228,28 @@ TEST(PrintfTest, Width) {
|
||||
EXPECT_PRINTF(" abc", "%5s", "abc");
|
||||
|
||||
// Width cannot be specified twice.
|
||||
EXPECT_THROW_MSG(test_sprintf("%5-5d", 42), format_error,
|
||||
"invalid type specifier");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%5-5d", 42), format_error, "invalid type specifier");
|
||||
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}d", BIG_NUM), 42),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%1${}d", BIG_NUM), 42),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf(format("%{}d", BIG_NUM), 42),
|
||||
format_error,
|
||||
"number is too big");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf(format("%1${}d", BIG_NUM), 42),
|
||||
format_error,
|
||||
"number is too big");
|
||||
}
|
||||
|
||||
TEST(PrintfTest, DynamicWidth) {
|
||||
EXPECT_EQ(" 42", test_sprintf("%*d", 5, 42));
|
||||
EXPECT_EQ("42 ", test_sprintf("%*d", -5, 42));
|
||||
EXPECT_THROW_MSG(test_sprintf("%*d", 5.0, 42), format_error,
|
||||
"width is not integer");
|
||||
EXPECT_THROW_MSG(test_sprintf("%*d"), format_error,
|
||||
"argument index out of range");
|
||||
EXPECT_THROW_MSG(test_sprintf("%*d", BIG_NUM, 42), format_error,
|
||||
"number is too big");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%*d", 5.0, 42), format_error, "width is not integer");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%*d"), format_error, "argument index out of range");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%*d", BIG_NUM, 42), format_error, "number is too big");
|
||||
}
|
||||
|
||||
TEST(PrintfTest, IntPrecision) {
|
||||
@ -266,25 +291,29 @@ TEST(PrintfTest, IgnorePrecisionForNonNumericArg) {
|
||||
TEST(PrintfTest, DynamicPrecision) {
|
||||
EXPECT_EQ("00042", test_sprintf("%.*d", 5, 42));
|
||||
EXPECT_EQ("42", test_sprintf("%.*d", -5, 42));
|
||||
EXPECT_THROW_MSG(test_sprintf("%.*d", 5.0, 42), format_error,
|
||||
"precision is not integer");
|
||||
EXPECT_THROW_MSG(test_sprintf("%.*d"), format_error,
|
||||
"argument index out of range");
|
||||
EXPECT_THROW_MSG(test_sprintf("%.*d", BIG_NUM, 42), format_error,
|
||||
"number is too big");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%.*d", 5.0, 42), format_error, "precision is not integer");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%.*d"), format_error, "argument index out of range");
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%.*d", BIG_NUM, 42), format_error, "number is too big");
|
||||
if (sizeof(long long) != sizeof(int)) {
|
||||
long long prec = static_cast<long long>(INT_MIN) - 1;
|
||||
EXPECT_THROW_MSG(test_sprintf("%.*d", prec, 42), format_error,
|
||||
"number is too big");
|
||||
}
|
||||
EXPECT_THROW_MSG(
|
||||
test_sprintf("%.*d", prec, 42), format_error, "number is too big");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct make_signed { typedef T type; };
|
||||
struct make_signed {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
#define SPECIALIZE_MAKE_SIGNED(T, S) \
|
||||
template <> \
|
||||
struct make_signed<T> { typedef S type; }
|
||||
template <> \
|
||||
struct make_signed<T> { \
|
||||
typedef S type; \
|
||||
}
|
||||
|
||||
SPECIALIZE_MAKE_SIGNED(char, signed char);
|
||||
SPECIALIZE_MAKE_SIGNED(unsigned char, signed char);
|
||||
@ -419,7 +448,7 @@ TEST(PrintfTest, Float) {
|
||||
|
||||
TEST(PrintfTest, Inf) {
|
||||
double inf = std::numeric_limits<double>::infinity();
|
||||
for (const char* type = "fega"; *type; ++type) {
|
||||
for (const char *type = "fega"; *type; ++type) {
|
||||
EXPECT_PRINTF("inf", fmt::format("%{}", *type), inf);
|
||||
char upper = static_cast<char>(std::toupper(*type));
|
||||
EXPECT_PRINTF("INF", fmt::format("%{}", upper), inf);
|
||||
@ -430,7 +459,7 @@ TEST(PrintfTest, Char) {
|
||||
EXPECT_PRINTF("x", "%c", 'x');
|
||||
int max = std::numeric_limits<int>::max();
|
||||
EXPECT_PRINTF(fmt::format("{}", static_cast<char>(max)), "%c", max);
|
||||
//EXPECT_PRINTF("x", "%lc", L'x');
|
||||
// EXPECT_PRINTF("x", "%lc", L'x');
|
||||
EXPECT_PRINTF(L"x", L"%c", L'x');
|
||||
EXPECT_PRINTF(fmt::format(L"{}", static_cast<wchar_t>(max)), L"%c", max);
|
||||
}
|
||||
@ -475,17 +504,17 @@ TEST(PrintfTest, Location) {
|
||||
|
||||
enum E { A = 42 };
|
||||
|
||||
TEST(PrintfTest, Enum) {
|
||||
EXPECT_PRINTF("42", "%d", A);
|
||||
}
|
||||
TEST(PrintfTest, Enum) { EXPECT_PRINTF("42", "%d", A); }
|
||||
|
||||
#if FMT_USE_FILE_DESCRIPTORS
|
||||
TEST(PrintfTest, Examples) {
|
||||
const char *weekday = "Thursday";
|
||||
const char *month = "August";
|
||||
int day = 21;
|
||||
EXPECT_WRITE(stdout, fmt::printf("%1$s, %3$d %2$s", weekday, month, day),
|
||||
"Thursday, 21 August");
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
fmt::printf("%1$s, %3$d %2$s", weekday, month, day),
|
||||
"Thursday, 21 August");
|
||||
}
|
||||
|
||||
TEST(PrintfTest, PrintfError) {
|
||||
@ -496,9 +525,7 @@ TEST(PrintfTest, PrintfError) {
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(PrintfTest, WideString) {
|
||||
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc"));
|
||||
}
|
||||
TEST(PrintfTest, WideString) { EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc")); }
|
||||
|
||||
TEST(PrintfTest, PrintfCustom) {
|
||||
EXPECT_EQ("abc", test_sprintf("%s", TestString("abc")));
|
||||
@ -520,8 +547,8 @@ TEST(PrintfTest, VPrintf) {
|
||||
EXPECT_WRITE(stdout, fmt::vfprintf(std::cout, "%d", args), "42");
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void check_format_string_regression(fmt::string_view s, const Args&... args) {
|
||||
template <typename... Args>
|
||||
void check_format_string_regression(fmt::string_view s, const Args &... args) {
|
||||
fmt::sprintf(s, args...);
|
||||
}
|
||||
|
||||
@ -530,17 +557,16 @@ TEST(PrintfTest, CheckFormatStringRegression) {
|
||||
}
|
||||
|
||||
TEST(PrintfTest, VSPrintfMakeArgsExample) {
|
||||
fmt::format_arg_store<fmt::printf_context, int, const char *> as{
|
||||
42, "something"};
|
||||
fmt::format_arg_store<fmt::printf_context, int, const char *> as{42,
|
||||
"something"};
|
||||
fmt::basic_format_args<fmt::printf_context> args(as);
|
||||
EXPECT_EQ(
|
||||
"[42] something happened", fmt::vsprintf("[%d] %s happened", args));
|
||||
EXPECT_EQ("[42] something happened", fmt::vsprintf("[%d] %s happened", args));
|
||||
auto as2 = fmt::make_printf_args(42, "something");
|
||||
fmt::basic_format_args<fmt::printf_context> args2(as2);
|
||||
EXPECT_EQ(
|
||||
"[42] something happened", fmt::vsprintf("[%d] %s happened", args2));
|
||||
//the older gcc versions can't cast the return value
|
||||
#if !defined(__GNUC__) || (__GNUC__ > 4)
|
||||
// the older gcc versions can't cast the return value
|
||||
#if !defined(__GNUC__) || (__GNUC__ > 4)
|
||||
EXPECT_EQ(
|
||||
"[42] something happened",
|
||||
fmt::vsprintf(
|
||||
@ -550,12 +576,11 @@ TEST(PrintfTest, VSPrintfMakeArgsExample) {
|
||||
|
||||
TEST(PrintfTest, VSPrintfMakeWArgsExample) {
|
||||
fmt::format_arg_store<fmt::wprintf_context, int, const wchar_t *> as{
|
||||
42, L"something"};
|
||||
42, L"something"};
|
||||
fmt::basic_format_args<fmt::wprintf_context> args(as);
|
||||
EXPECT_EQ(
|
||||
L"[42] something happened",
|
||||
fmt::vsprintf(L"[%d] %s happened", args));
|
||||
auto as2 = fmt::make_wprintf_args(42, L"something");
|
||||
L"[42] something happened", fmt::vsprintf(L"[%d] %s happened", args));
|
||||
auto as2 = fmt::make_wprintf_args(42, L"something");
|
||||
fmt::basic_format_args<fmt::wprintf_context> args2(as2);
|
||||
EXPECT_EQ(
|
||||
L"[42] something happened", fmt::vsprintf(L"[%d] %s happened", args2));
|
||||
|
||||
@ -16,10 +16,10 @@
|
||||
#include "fmt/ranges.h"
|
||||
#include "gtest.h"
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
TEST(RangesTest, FormatVector) {
|
||||
std::vector<int32_t> iv{1, 2, 3, 5, 7, 11};
|
||||
@ -44,8 +44,8 @@ TEST(RangesTest, FormatPair) {
|
||||
}
|
||||
|
||||
TEST(RangesTest, FormatTuple) {
|
||||
std::tuple<int64_t, float, std::string, char> tu1{42, 3.14159265358979f,
|
||||
"this is tuple", 'i'};
|
||||
std::tuple<int64_t, float, std::string, char> tu1{
|
||||
42, 3.14159265358979f, "this is tuple", 'i'};
|
||||
EXPECT_EQ("(42, 3.14159, \"this is tuple\", 'i')", fmt::format("{}", tu1));
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,8 @@ class assertion_failure : public std::logic_error {
|
||||
};
|
||||
|
||||
#define FMT_ASSERT(condition, message) \
|
||||
if (!(condition)) throw assertion_failure(message);
|
||||
if (!(condition)) \
|
||||
throw assertion_failure(message);
|
||||
|
||||
// Expects an assertion failure.
|
||||
#define EXPECT_ASSERT(stmt, message) \
|
||||
|
||||
@ -9,14 +9,14 @@
|
||||
#include "gtest.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# include <crtdbg.h>
|
||||
#include <crtdbg.h>
|
||||
#else
|
||||
# define _CrtSetReportFile(a, b)
|
||||
# define _CrtSetReportMode(a, b)
|
||||
#define _CrtSetReportFile(a, b)
|
||||
#define _CrtSetReportMode(a, b)
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@ -24,8 +24,8 @@ int main(int argc, char **argv) {
|
||||
// Don't display any error dialogs. This also suppresses message boxes
|
||||
// on assertion failures in MinGW where _set_error_mode/CrtSetReportMode
|
||||
// doesn't help.
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
|
||||
SEM_NOOPENFILEERRORBOX);
|
||||
SetErrorMode(
|
||||
SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
|
||||
#endif
|
||||
// Disable message boxes on assertion failures.
|
||||
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
||||
|
||||
@ -9,23 +9,22 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "gmock.h"
|
||||
#include "fmt/locale.h"
|
||||
#include "fmt/time.h"
|
||||
#include "fmt/locale.h"
|
||||
#include "gmock.h"
|
||||
|
||||
TEST(TimeTest, Format) {
|
||||
std::tm tm = std::tm();
|
||||
tm.tm_year = 116;
|
||||
tm.tm_mon = 3;
|
||||
tm.tm_mon = 3;
|
||||
tm.tm_mday = 25;
|
||||
EXPECT_EQ("The date is 2016-04-25.",
|
||||
fmt::format("The date is {:%Y-%m-%d}.", tm));
|
||||
EXPECT_EQ(
|
||||
"The date is 2016-04-25.", fmt::format("The date is {:%Y-%m-%d}.", tm));
|
||||
}
|
||||
|
||||
TEST(TimeTest, GrowBuffer) {
|
||||
std::string s = "{:";
|
||||
for (int i = 0; i < 30; ++i)
|
||||
s += "%c";
|
||||
for (int i = 0; i < 30; ++i) s += "%c";
|
||||
s += "}\n";
|
||||
std::time_t t = std::time(FMT_NULL);
|
||||
fmt::format(s, *std::localtime(&t));
|
||||
@ -39,19 +38,13 @@ TEST(TimeTest, FormatToEmptyContainer) {
|
||||
EXPECT_EQ(s, "42");
|
||||
}
|
||||
|
||||
TEST(TimeTest, EmptyResult) {
|
||||
EXPECT_EQ("", fmt::format("{}", std::tm()));
|
||||
}
|
||||
TEST(TimeTest, EmptyResult) { EXPECT_EQ("", fmt::format("{}", std::tm())); }
|
||||
|
||||
static bool EqualTime(const std::tm &lhs, const std::tm &rhs) {
|
||||
return lhs.tm_sec == rhs.tm_sec &&
|
||||
lhs.tm_min == rhs.tm_min &&
|
||||
lhs.tm_hour == rhs.tm_hour &&
|
||||
lhs.tm_mday == rhs.tm_mday &&
|
||||
lhs.tm_mon == rhs.tm_mon &&
|
||||
lhs.tm_year == rhs.tm_year &&
|
||||
lhs.tm_wday == rhs.tm_wday &&
|
||||
lhs.tm_yday == rhs.tm_yday &&
|
||||
return lhs.tm_sec == rhs.tm_sec && lhs.tm_min == rhs.tm_min &&
|
||||
lhs.tm_hour == rhs.tm_hour && lhs.tm_mday == rhs.tm_mday &&
|
||||
lhs.tm_mon == rhs.tm_mon && lhs.tm_year == rhs.tm_year &&
|
||||
lhs.tm_wday == rhs.tm_wday && lhs.tm_yday == rhs.tm_yday &&
|
||||
lhs.tm_isdst == rhs.tm_isdst;
|
||||
}
|
||||
|
||||
|
||||
@ -11,12 +11,12 @@
|
||||
|
||||
#include "fmt/posix.h"
|
||||
|
||||
enum {BUFFER_SIZE = 256};
|
||||
enum { BUFFER_SIZE = 256 };
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define FMT_VSNPRINTF vsprintf_s
|
||||
#define FMT_VSNPRINTF vsprintf_s
|
||||
#else
|
||||
# define FMT_VSNPRINTF vsnprintf
|
||||
#define FMT_VSNPRINTF vsnprintf
|
||||
#endif
|
||||
|
||||
template <std::size_t SIZE>
|
||||
@ -76,6 +76,7 @@ std::basic_ostream<Char> &operator<<(
|
||||
|
||||
class Date {
|
||||
int year_, month_, day_;
|
||||
|
||||
public:
|
||||
Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user