Format the code using clang-format

This commit is contained in:
Victor Zverovich 2019-01-12 18:27:38 -08:00
parent 9a777b9e1c
commit 58b6f8db48
39 changed files with 4734 additions and 5108 deletions

8
.clang-format Normal file
View File

@ -0,0 +1,8 @@
# Run manually to reformat a file:
# clang-format -i --style=file <file>
Language: Cpp
BasedOnStyle: Google
IndentPPDirectives: AfterHash
IndentCaseLabels: false
AlwaysBreakTemplateDeclarations: false
DerivePointerAlignment: false

View File

@ -28,8 +28,9 @@ enum class numeric_system {
// Parses a put_time-like format string and invokes handler actions. // Parses a put_time-like format string and invokes handler actions.
template <typename Char, typename Handler> template <typename Char, typename Handler>
FMT_CONSTEXPR const Char *parse_chrono_format( FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
const Char *begin, const Char *end, Handler &&handler) { const Char* end,
Handler&& handler) {
auto ptr = begin; auto ptr = begin;
while (ptr != end) { while (ptr != end) {
auto c = *ptr; auto c = *ptr;
@ -38,11 +39,9 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
++ptr; ++ptr;
continue; continue;
} }
if (begin != ptr) if (begin != ptr) handler.on_text(begin, ptr);
handler.on_text(begin, ptr);
++ptr; // consume '%' ++ptr; // consume '%'
if (ptr == end) if (ptr == end) throw format_error("invalid format");
throw format_error("invalid format");
c = *ptr++; c = *ptr++;
switch (c) { switch (c) {
case '%': case '%':
@ -127,8 +126,7 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
break; break;
// Alternative representation: // Alternative representation:
case 'E': { case 'E': {
if (ptr == end) if (ptr == end) throw format_error("invalid format");
throw format_error("invalid format");
c = *ptr++; c = *ptr++;
switch (c) { switch (c) {
case 'c': case 'c':
@ -146,8 +144,7 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
break; break;
} }
case 'O': case 'O':
if (ptr == end) if (ptr == end) throw format_error("invalid format");
throw format_error("invalid format");
c = *ptr++; c = *ptr++;
switch (c) { switch (c) {
case 'w': case 'w':
@ -177,16 +174,14 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
} }
begin = ptr; begin = ptr;
} }
if (begin != ptr) if (begin != ptr) handler.on_text(begin, ptr);
handler.on_text(begin, ptr);
return ptr; return ptr;
} }
struct chrono_format_checker { struct chrono_format_checker {
void report_no_date() { throw format_error("no date"); } void report_no_date() { throw format_error("no date"); }
template <typename Char> template <typename Char> void on_text(const Char*, const Char*) {}
void on_text(const Char *, const Char *) {}
void on_abbr_weekday() { report_no_date(); } void on_abbr_weekday() { report_no_date(); }
void on_full_weekday() { report_no_date(); } void on_full_weekday() { report_no_date(); }
void on_dec0_weekday(numeric_system) { report_no_date(); } void on_dec0_weekday(numeric_system) { report_no_date(); }
@ -210,15 +205,14 @@ struct chrono_format_checker {
void on_tz_name() { report_no_date(); } void on_tz_name() { report_no_date(); }
}; };
template <typename Int> template <typename Int> inline int to_int(Int value) {
inline int to_int(Int value) {
FMT_ASSERT(value >= (std::numeric_limits<int>::min)() && FMT_ASSERT(value >= (std::numeric_limits<int>::min)() &&
value <= (std::numeric_limits<int>::max)(), "invalid value"); value <= (std::numeric_limits<int>::max)(),
"invalid value");
return static_cast<int>(value); return static_cast<int>(value);
} }
template <typename FormatContext, typename OutputIt> template <typename FormatContext, typename OutputIt> struct chrono_formatter {
struct chrono_formatter {
FormatContext& context; FormatContext& context;
OutputIt out; OutputIt out;
std::chrono::seconds s; std::chrono::seconds s;
@ -251,8 +245,7 @@ struct chrono_formatter {
typedef typename int_traits<int>::main_type main_type; typedef typename int_traits<int>::main_type main_type;
main_type n = to_unsigned(value); main_type n = to_unsigned(value);
int num_digits = internal::count_digits(n); int num_digits = internal::count_digits(n);
if (width > num_digits) if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
out = std::fill_n(out, width - num_digits, '0');
out = format_decimal<char_type>(out, n, num_digits); out = format_decimal<char_type>(out, n, num_digits);
} }
@ -286,24 +279,21 @@ struct chrono_formatter {
void on_tz_name() {} void on_tz_name() {}
void on_24_hour(numeric_system ns) { void on_24_hour(numeric_system ns) {
if (ns == numeric_system::standard) if (ns == numeric_system::standard) return write(hour(), 2);
return write(hour(), 2);
auto time = tm(); auto time = tm();
time.tm_hour = hour(); time.tm_hour = hour();
format_localized(time, "%OH"); format_localized(time, "%OH");
} }
void on_12_hour(numeric_system ns) { void on_12_hour(numeric_system ns) {
if (ns == numeric_system::standard) if (ns == numeric_system::standard) return write(hour12(), 2);
return write(hour12(), 2);
auto time = tm(); auto time = tm();
time.tm_hour = hour(); time.tm_hour = hour();
format_localized(time, "%OI"); format_localized(time, "%OI");
} }
void on_minute(numeric_system ns) { void on_minute(numeric_system ns) {
if (ns == numeric_system::standard) if (ns == numeric_system::standard) return write(minute(), 2);
return write(minute(), 2);
auto time = tm(); auto time = tm();
time.tm_min = minute(); time.tm_min = minute();
format_localized(time, "%OM"); format_localized(time, "%OM");
@ -382,8 +372,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
basic_parse_context<Char>& context; basic_parse_context<Char>& context;
basic_string_view<Char> format_str; basic_string_view<Char> format_str;
template <typename Id> template <typename Id> FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
context.check_arg_id(arg_id); context.check_arg_id(arg_id);
return arg_ref_type(arg_id); return arg_ref_type(arg_id);
} }
@ -403,8 +392,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
void on_align(alignment align) { f.spec.align_ = align; } void on_align(alignment align) { f.spec.align_ = align; }
void on_width(unsigned width) { f.spec.width_ = width; } void on_width(unsigned width) { f.spec.width_ = width; }
template <typename Id> template <typename Id> void on_dynamic_width(Id arg_id) {
void on_dynamic_width(Id arg_id) {
f.width_ref = make_arg_ref(arg_id); f.width_ref = make_arg_ref(arg_id);
} }
}; };
@ -421,14 +409,13 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
if (begin == end) return begin; if (begin == end) return begin;
begin = internal::parse_width(begin, end, handler); begin = internal::parse_width(begin, end, handler);
end = parse_chrono_format(begin, end, internal::chrono_format_checker()); end = parse_chrono_format(begin, end, internal::chrono_format_checker());
format_str = basic_string_view<Char>( format_str =
&*begin, internal::to_unsigned(end - begin)); basic_string_view<Char>(&*begin, internal::to_unsigned(end - begin));
return end; return end;
} }
template <typename FormatContext> template <typename FormatContext>
auto format(const duration &d, FormatContext &ctx) auto format(const duration& d, FormatContext& ctx) -> decltype(ctx.out()) {
-> decltype(ctx.out()) {
auto begin = format_str.begin(), end = format_str.end(); auto begin = format_str.begin(), end = format_str.end();
// As a possible future optimization, we could avoid extra copying if width // As a possible future optimization, we could avoid extra copying if width
// is not specified. // is not specified.
@ -449,8 +436,8 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s); f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s);
parse_chrono_format(begin, end, f); parse_chrono_format(begin, end, f);
} }
internal::handle_dynamic_spec<internal::width_checker>( internal::handle_dynamic_spec<internal::width_checker>(spec.width_,
spec.width_, width_ref, ctx); width_ref, ctx);
w.write(buf.data(), buf.size(), spec); w.write(buf.data(), buf.size(), spec);
return w.out(); return w.out();
} }

View File

@ -226,7 +226,8 @@ struct rgb {
FMT_CONSTEXPR rgb(uint32_t hex) FMT_CONSTEXPR rgb(uint32_t hex)
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {} : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {}
FMT_CONSTEXPR rgb(color hex) FMT_CONSTEXPR rgb(color hex)
: r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF), : r((uint32_t(hex) >> 16) & 0xFF),
g((uint32_t(hex) >> 8) & 0xFF),
b(uint32_t(hex) & 0xFF) {} b(uint32_t(hex) & 0xFF) {}
uint8_t r; uint8_t r;
uint8_t g; uint8_t g;
@ -237,19 +238,17 @@ namespace internal {
// color is a struct of either a rgb color or a terminal color. // color is a struct of either a rgb color or a terminal color.
struct color_type { struct color_type {
FMT_CONSTEXPR color_type() FMT_NOEXCEPT FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
: is_rgb(), value{} {} FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT value{} {
: is_rgb(true), value{} {
value.rgb_color = static_cast<uint32_t>(rgb_color); value.rgb_color = static_cast<uint32_t>(rgb_color);
} }
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} {
: is_rgb(true), value{} { value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
| (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
} }
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
: is_rgb(), value{} { value{} {
value.term_color = static_cast<uint8_t>(term_color); value.term_color = static_cast<uint8_t>(term_color);
} }
bool is_rgb; bool is_rgb;
@ -264,7 +263,9 @@ struct color_type {
class text_style { class text_style {
public: public:
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
: set_foreground_color(), set_background_color(), ems(em) {} : set_foreground_color(),
set_background_color(),
ems(em) {}
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) { FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
if (!set_foreground_color) { if (!set_foreground_color) {
@ -290,8 +291,8 @@ class text_style {
return *this; return *this;
} }
friend FMT_CONSTEXPR friend FMT_CONSTEXPR text_style operator|(text_style lhs,
text_style operator|(text_style lhs, const text_style &rhs) { const text_style& rhs) {
return lhs |= rhs; return lhs |= rhs;
} }
@ -319,8 +320,8 @@ class text_style {
return *this; return *this;
} }
friend FMT_CONSTEXPR friend FMT_CONSTEXPR text_style operator&(text_style lhs,
text_style operator&(text_style lhs, const text_style &rhs) { const text_style& rhs) {
return lhs &= rhs; return lhs &= rhs;
} }
@ -387,8 +388,7 @@ FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
namespace internal { namespace internal {
template <typename Char> template <typename Char> struct ansi_color_escape {
struct ansi_color_escape {
FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color, FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
const char* esc) FMT_NOEXCEPT { const char* esc) FMT_NOEXCEPT {
// If we have a terminal color, we need to output another escape code // If we have a terminal color, we need to output another escape code
@ -398,8 +398,7 @@ struct ansi_color_escape {
uint32_t value = text_color.value.term_color; uint32_t value = text_color.value.term_color;
// Background ASCII codes are the same as the foreground ones but with // Background ASCII codes are the same as the foreground ones but with
// 10 more. // 10 more.
if (is_background) if (is_background) value += 10u;
value += 10u;
std::size_t index = 0; std::size_t index = 0;
buffer[index++] = static_cast<Char>('\x1b'); buffer[index++] = static_cast<Char>('\x1b');
@ -429,19 +428,15 @@ struct ansi_color_escape {
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT { FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
uint8_t em_codes[4] = {}; uint8_t em_codes[4] = {};
uint8_t em_bits = static_cast<uint8_t>(em); uint8_t em_bits = static_cast<uint8_t>(em);
if (em_bits & static_cast<uint8_t>(emphasis::bold)) if (em_bits & static_cast<uint8_t>(emphasis::bold)) em_codes[0] = 1;
em_codes[0] = 1; if (em_bits & static_cast<uint8_t>(emphasis::italic)) em_codes[1] = 3;
if (em_bits & static_cast<uint8_t>(emphasis::italic)) if (em_bits & static_cast<uint8_t>(emphasis::underline)) em_codes[2] = 4;
em_codes[1] = 3;
if (em_bits & static_cast<uint8_t>(emphasis::underline))
em_codes[2] = 4;
if (em_bits & static_cast<uint8_t>(emphasis::strikethrough)) if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
em_codes[3] = 9; em_codes[3] = 9;
std::size_t index = 0; std::size_t index = 0;
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
if (!em_codes[i]) if (!em_codes[i]) continue;
continue;
buffer[index++] = static_cast<Char>('\x1b'); buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('['); buffer[index++] = static_cast<Char>('[');
buffer[index++] = static_cast<Char>('0' + em_codes[i]); buffer[index++] = static_cast<Char>('0' + em_codes[i]);
@ -451,9 +446,7 @@ struct ansi_color_escape {
} }
FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; } FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
FMT_CONSTEXPR const Char * begin() const FMT_NOEXCEPT { FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
return buffer;
}
FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT { FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT {
return buffer + std::strlen(buffer); return buffer + std::strlen(buffer);
} }
@ -471,20 +464,19 @@ private:
}; };
template <typename Char> template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
make_foreground_color(internal::color_type foreground) FMT_NOEXCEPT { internal::color_type foreground) FMT_NOEXCEPT {
return ansi_color_escape<Char>(foreground, internal::data::FOREGROUND_COLOR); return ansi_color_escape<Char>(foreground, internal::data::FOREGROUND_COLOR);
} }
template <typename Char> template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
make_background_color(internal::color_type background) FMT_NOEXCEPT { internal::color_type background) FMT_NOEXCEPT {
return ansi_color_escape<Char>(background, internal::data::BACKGROUND_COLOR); return ansi_color_escape<Char>(background, internal::data::BACKGROUND_COLOR);
} }
template <typename Char> template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT {
make_emphasis(emphasis em) FMT_NOEXCEPT {
return ansi_color_escape<Char>(em); return ansi_color_escape<Char>(em);
} }
@ -498,13 +490,11 @@ inline void fputs<wchar_t>(const wchar_t *chars, FILE *stream) FMT_NOEXCEPT {
std::fputws(chars, stream); std::fputws(chars, stream);
} }
template <typename Char> template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
inline void reset_color(FILE *stream) FMT_NOEXCEPT {
fputs(internal::data::RESET_COLOR, stream); fputs(internal::data::RESET_COLOR, stream);
} }
template <> template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
inline void reset_color<wchar_t>(FILE *stream) FMT_NOEXCEPT {
fputs(internal::data::WRESET_COLOR, stream); fputs(internal::data::WRESET_COLOR, stream);
} }
@ -519,10 +509,8 @@ inline void reset_color(basic_memory_buffer<Char>& buffer) FMT_NOEXCEPT {
// which is needed because or else // which is needed because or else
// fmt::print(stderr, fmt::emphasis::bold, ""); // fmt::print(stderr, fmt::emphasis::bold, "");
// would take stderr (a std::FILE *) as the format string. // would take stderr (a std::FILE *) as the format string.
template <> template <> struct is_string<std::FILE*> : std::false_type {};
struct is_string<std::FILE *> : std::false_type {}; template <> struct is_string<const std::FILE*> : std::false_type {};
template <>
struct is_string<const std::FILE *> : std::false_type {};
template <typename Char> template <typename Char>
std::basic_string<Char> vformat( std::basic_string<Char> vformat(
@ -532,8 +520,7 @@ std::basic_string<Char> vformat(
bool has_style = false; bool has_style = false;
if (ts.has_emphasis()) { if (ts.has_emphasis()) {
has_style = true; has_style = true;
ansi_color_escape<Char> escape = ansi_color_escape<Char> escape = make_emphasis<Char>(ts.get_emphasis());
make_emphasis<Char>(ts.get_emphasis());
buffer.append(escape.begin(), escape.end()); buffer.append(escape.begin(), escape.end());
} }
if (ts.has_foreground()) { if (ts.has_foreground()) {
@ -556,15 +543,13 @@ std::basic_string<Char> vformat(
} }
} // namespace internal } // namespace internal
template < template <typename S, typename Char = typename internal::char_t<S>::type>
typename S, typename Char = typename internal::char_t<S>::type>
void vprint(std::FILE* f, const text_style& ts, const S& format, void vprint(std::FILE* f, const text_style& ts, const S& format,
basic_format_args<typename buffer_context<Char>::type> args) { basic_format_args<typename buffer_context<Char>::type> args) {
bool has_style = false; bool has_style = false;
if (ts.has_emphasis()) { if (ts.has_emphasis()) {
has_style = true; has_style = true;
internal::fputs<Char>( internal::fputs<Char>(internal::make_emphasis<Char>(ts.get_emphasis()), f);
internal::make_emphasis<Char>(ts.get_emphasis()), f);
} }
if (ts.has_foreground()) { if (ts.has_foreground()) {
has_style = true; has_style = true;
@ -609,16 +594,13 @@ typename std::enable_if<internal::is_string<String>::value>::type print(
*/ */
template <typename String, typename... Args> template <typename String, typename... Args>
typename std::enable_if<internal::is_string<String>::value>::type print( typename std::enable_if<internal::is_string<String>::value>::type print(
const text_style &ts, const String &format_str, const text_style& ts, const String& format_str, const Args&... args) {
const Args &... args) {
return print(stdout, ts, format_str, args...); return print(stdout, ts, format_str, args...);
} }
template <typename S, typename Char = FMT_CHAR(S)> template <typename S, typename Char = FMT_CHAR(S)>
inline std::basic_string<Char> vformat( inline std::basic_string<Char> vformat(
const text_style &ts, const text_style& ts, const S& format_str,
const S &format_str,
basic_format_args<typename buffer_context<Char>::type> args) { basic_format_args<typename buffer_context<Char>::type> args) {
return internal::vformat(ts, to_string_view(format_str), args); return internal::vformat(ts, to_string_view(format_str), args);
} }
@ -636,8 +618,9 @@ inline std::basic_string<Char> vformat(
\endrst \endrst
*/ */
template <typename S, typename... Args> template <typename S, typename... Args>
inline std::basic_string<FMT_CHAR(S)> format( inline std::basic_string<FMT_CHAR(S)> format(const text_style& ts,
const text_style &ts, const S &format_str, const Args &... args) { const S& format_str,
const Args&... args) {
return internal::vformat( return internal::vformat(
ts, to_string_view(format_str), ts, to_string_view(format_str),
*internal::checked_args<S, Args...>(format_str, args...)); *internal::checked_args<S, Args...>(format_str, args...));

View File

@ -89,8 +89,8 @@
# endif # endif
#endif #endif
#if FMT_HAS_FEATURE(cxx_explicit_conversions) || \ #if FMT_HAS_FEATURE(cxx_explicit_conversions) || FMT_GCC_VERSION >= 405 || \
FMT_GCC_VERSION >= 405 || FMT_MSC_VER >= 1800 FMT_MSC_VER >= 1800
# define FMT_USE_EXPLICIT 1 # define FMT_USE_EXPLICIT 1
# define FMT_EXPLICIT explicit # define FMT_EXPLICIT explicit
#else #else
@ -147,12 +147,19 @@
# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \ # if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
FMT_MSC_VER >= 1900 FMT_MSC_VER >= 1900
# define FMT_INLINE_NAMESPACE inline namespace # define FMT_INLINE_NAMESPACE inline namespace
# define FMT_END_NAMESPACE }} # define FMT_END_NAMESPACE \
} \
}
# else # else
# define FMT_INLINE_NAMESPACE namespace # define FMT_INLINE_NAMESPACE namespace
# define FMT_END_NAMESPACE } using namespace v5; } # define FMT_END_NAMESPACE \
} \
using namespace v5; \
}
# endif # endif
# define FMT_BEGIN_NAMESPACE namespace fmt { FMT_INLINE_NAMESPACE v5 { # define FMT_BEGIN_NAMESPACE \
namespace fmt { \
FMT_INLINE_NAMESPACE v5 {
#endif #endif
#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) #if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
@ -193,14 +200,12 @@ namespace internal {
template <typename T> template <typename T>
typename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT; typename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT;
template <typename> template <typename> struct result_of;
struct result_of;
template <typename F, typename... Args> template <typename F, typename... Args> struct result_of<F(Args...)> {
struct result_of<F(Args...)> {
// A workaround for gcc 4.4 that doesn't allow F to be a reference. // A workaround for gcc 4.4 that doesn't allow F to be a reference.
typedef typename std::result_of< typedef typename std::result_of<typename std::remove_reference<F>::type(
typename std::remove_reference<F>::type(Args...)>::type type; Args...)>::type type;
}; };
// Casts nonnegative integer to unsigned. // Casts nonnegative integer to unsigned.
@ -211,8 +216,7 @@ FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
} }
/** A contiguous memory buffer with an optional growing ability. */ /** A contiguous memory buffer with an optional growing ability. */
template <typename T> template <typename T> class basic_buffer {
class basic_buffer {
private: private:
basic_buffer(const basic_buffer&) = delete; basic_buffer(const basic_buffer&) = delete;
void operator=(const basic_buffer&) = delete; void operator=(const basic_buffer&) = delete;
@ -225,8 +229,10 @@ class basic_buffer {
// Don't initialize ptr_ since it is not accessed to save a few cycles. // 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(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) basic_buffer(T* p = FMT_NULL, std::size_t sz = 0,
FMT_NOEXCEPT: ptr_(p), size_(sz), capacity_(cap) {} std::size_t cap = 0) FMT_NOEXCEPT : ptr_(p),
size_(sz),
capacity_(cap) {}
/** Sets the buffer data and capacity. */ /** Sets the buffer data and capacity. */
void set(T* buf_data, std::size_t buf_capacity) FMT_NOEXCEPT { void set(T* buf_data, std::size_t buf_capacity) FMT_NOEXCEPT {
@ -271,8 +277,7 @@ class basic_buffer {
/** Reserves space to store at least *capacity* elements. */ /** Reserves space to store at least *capacity* elements. */
void reserve(std::size_t new_capacity) { void reserve(std::size_t new_capacity) {
if (new_capacity > capacity_) if (new_capacity > capacity_) grow(new_capacity);
grow(new_capacity);
} }
void push_back(const T& value) { void push_back(const T& value) {
@ -281,8 +286,7 @@ class basic_buffer {
} }
/** Appends data to the end of the buffer. */ /** Appends data to the end of the buffer. */
template <typename U> template <typename U> void append(const U* begin, const U* end);
void append(const U *begin, const U *end);
T& operator[](std::size_t index) { return ptr_[index]; } T& operator[](std::size_t index) { return ptr_[index]; }
const T& operator[](std::size_t index) const { return ptr_[index]; } const T& operator[](std::size_t index) const { return ptr_[index]; }
@ -327,13 +331,11 @@ struct error_handler {
FMT_API void on_error(const char* message); FMT_API void on_error(const char* message);
}; };
template <typename T> template <typename T> struct no_formatter_error : std::false_type {};
struct no_formatter_error : std::false_type {};
} // namespace internal } // namespace internal
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 405 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 405
template <typename... T> template <typename... T> struct is_constructible : std::false_type {};
struct is_constructible: std::false_type {};
#else #else
template <typename... T> template <typename... T>
struct is_constructible : std::is_constructible<T...> {}; struct is_constructible : std::is_constructible<T...> {};
@ -346,8 +348,7 @@ struct is_constructible : std::is_constructible<T...> {};
compiled with a different ``-std`` option than the client code (which is not compiled with a different ``-std`` option than the client code (which is not
recommended). recommended).
*/ */
template <typename Char> template <typename Char> class basic_string_view {
class basic_string_view {
private: private:
const Char* data_; const Char* data_;
size_t size_; size_t size_;
@ -360,7 +361,8 @@ class basic_string_view {
/** Constructs a string reference object from a C string and a size. */ /** Constructs a string reference object from a C string and a size. */
FMT_CONSTEXPR basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT FMT_CONSTEXPR basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT
: data_(s), size_(count) {} : data_(s),
size_(count) {}
/** /**
\rst \rst
@ -373,13 +375,14 @@ class basic_string_view {
/** Constructs a string reference from a ``std::basic_string`` object. */ /** Constructs a string reference from a ``std::basic_string`` object. */
template <typename Alloc> template <typename Alloc>
FMT_CONSTEXPR basic_string_view( FMT_CONSTEXPR basic_string_view(const std::basic_string<Char, Alloc>& s)
const std::basic_string<Char, Alloc> &s) FMT_NOEXCEPT FMT_NOEXCEPT : data_(s.data()),
: data_(s.data()), size_(s.size()) {} size_(s.size()) {}
#ifdef FMT_STRING_VIEW #ifdef FMT_STRING_VIEW
FMT_CONSTEXPR basic_string_view(FMT_STRING_VIEW<Char> s) FMT_NOEXCEPT FMT_CONSTEXPR basic_string_view(FMT_STRING_VIEW<Char> s) FMT_NOEXCEPT
: data_(s.data()), size_(s.size()) {} : data_(s.data()),
size_(s.size()) {}
#endif #endif
/** Returns a pointer to the string data. */ /** Returns a pointer to the string data. */
@ -451,22 +454,26 @@ typedef basic_string_view<wchar_t> wstring_view;
\endrst \endrst
*/ */
template <typename Char> template <typename Char>
inline basic_string_view<Char> inline basic_string_view<Char> to_string_view(basic_string_view<Char> s) {
to_string_view(basic_string_view<Char> s) { return s; } return s;
}
template <typename Char, typename Traits, typename Allocator> template <typename Char, typename Traits, typename Allocator>
inline basic_string_view<Char> inline basic_string_view<Char> to_string_view(
to_string_view(const std::basic_string<Char, Traits, Allocator> &s) { const std::basic_string<Char, Traits, Allocator>& s) {
return {s.data(), s.size()}; return {s.data(), s.size()};
} }
template <typename Char> template <typename Char>
inline basic_string_view<Char> to_string_view(const Char *s) { return s; } inline basic_string_view<Char> to_string_view(const Char* s) {
return s;
}
#ifdef FMT_STRING_VIEW #ifdef FMT_STRING_VIEW
template <typename Char> template <typename Char>
inline basic_string_view<Char> inline basic_string_view<Char> to_string_view(FMT_STRING_VIEW<Char> s) {
to_string_view(FMT_STRING_VIEW<Char> s) { return s; } return s;
}
#endif #endif
// A base class for compile-time strings. It is defined in the fmt namespace to // A base class for compile-time strings. It is defined in the fmt namespace to
@ -476,22 +483,22 @@ struct compile_string {};
template <typename S> template <typename S>
struct is_compile_string : std::is_base_of<compile_string, S> {}; struct is_compile_string : std::is_base_of<compile_string, S> {};
template < template <typename S, typename Enable = typename std::enable_if<
typename S, is_compile_string<S>::value>::type>
typename Enable = typename std::enable_if<is_compile_string<S>::value>::type> FMT_CONSTEXPR basic_string_view<typename S::char_type> to_string_view(
FMT_CONSTEXPR basic_string_view<typename S::char_type> const S& s) {
to_string_view(const S &s) { return s; } return s;
}
template <typename Context> template <typename Context> class basic_format_arg;
class basic_format_arg;
template <typename Context> template <typename Context> class basic_format_args;
class basic_format_args;
// A formatter for objects of type T. // A formatter for objects of type T.
template <typename T, typename Char = char, typename Enable = void> template <typename T, typename Char = char, typename Enable = void>
struct formatter { struct formatter {
static_assert(internal::no_formatter_error<T>::value, static_assert(
internal::no_formatter_error<T>::value,
"don't know how to format the type, include fmt/ostream.h if it provides " "don't know how to format the type, include fmt/ostream.h if it provides "
"an operator<< that should be used"); "an operator<< that should be used");
@ -503,40 +510,54 @@ struct formatter {
}; };
template <typename T, typename Char, typename Enable = void> template <typename T, typename Char, typename Enable = void>
struct convert_to_int: std::integral_constant< struct convert_to_int
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 { namespace internal {
struct dummy_string_view { typedef void char_type; }; struct dummy_string_view {
typedef void char_type;
};
dummy_string_view to_string_view(...); dummy_string_view to_string_view(...);
using fmt::v5::to_string_view; using fmt::v5::to_string_view;
// Specifies whether S is a string type convertible to fmt::basic_string_view. // Specifies whether S is a string type convertible to fmt::basic_string_view.
template <typename S> template <typename S>
struct is_string : std::integral_constant<bool, !std::is_same< struct is_string
dummy_string_view, decltype(to_string_view(declval<S>()))>::value> {}; : std::integral_constant<
bool, !std::is_same<dummy_string_view,
decltype(to_string_view(declval<S>()))>::value> {
};
template <typename S> template <typename S> struct char_t {
struct char_t {
typedef decltype(to_string_view(declval<S>())) result; typedef decltype(to_string_view(declval<S>())) result;
typedef typename result::char_type type; typedef typename result::char_type type;
}; };
template <typename Char> template <typename Char> struct named_arg_base;
struct named_arg_base;
template <typename T, typename Char> template <typename T, typename Char> struct named_arg;
struct named_arg;
enum type { enum type {
none_type, named_arg_type, none_type,
named_arg_type,
// Integer types should go first, // Integer types should go first,
int_type, uint_type, long_long_type, ulong_long_type, bool_type, char_type, int_type,
uint_type,
long_long_type,
ulong_long_type,
bool_type,
char_type,
last_integer_type = char_type, last_integer_type = char_type,
// followed by floating-point types. // followed by floating-point types.
double_type, long_double_type, last_numeric_type = long_double_type, double_type,
cstring_type, string_type, pointer_type, custom_type long_double_type,
last_numeric_type = long_double_type,
cstring_type,
string_type,
pointer_type,
custom_type
}; };
FMT_CONSTEXPR bool is_integral(type t) { FMT_CONSTEXPR bool is_integral(type t) {
@ -549,21 +570,18 @@ FMT_CONSTEXPR bool is_arithmetic(type t) {
return t > internal::none_type && t <= internal::last_numeric_type; return t > internal::none_type && t <= internal::last_numeric_type;
} }
template <typename Char> template <typename Char> struct string_value {
struct string_value {
const Char* value; const Char* value;
std::size_t size; std::size_t size;
}; };
template <typename Context> template <typename Context> struct custom_value {
struct custom_value {
const void* value; const void* value;
void (*format)(const void* arg, Context& ctx); void (*format)(const void* arg, Context& ctx);
}; };
// A formatting argument value. // A formatting argument value.
template <typename Context> template <typename Context> class value {
class value {
public: public:
typedef typename Context::char_type char_type; typedef typename Context::char_type char_type;
@ -604,8 +622,7 @@ class value {
} }
value(const void* val) { pointer = val; } value(const void* val) { pointer = val; }
template <typename T> template <typename T> explicit value(const T& val) {
explicit value(const T &val) {
custom.value = &val; custom.value = &val;
custom.format = &format_custom_arg<T>; custom.format = &format_custom_arg<T>;
} }
@ -629,8 +646,7 @@ class value {
}; };
// Value initializer used to delay conversion to value and reduce memory churn. // Value initializer used to delay conversion to value and reduce memory churn.
template <typename Context, typename T, type TYPE> template <typename Context, typename T, type TYPE> struct init {
struct init {
T val; T val;
static const type type_tag = TYPE; static const type type_tag = TYPE;
@ -649,7 +665,9 @@ FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value);
#define FMT_MAKE_VALUE_SAME(TAG, Type) \ #define FMT_MAKE_VALUE_SAME(TAG, Type) \
template <typename C> \ template <typename C> \
FMT_CONSTEXPR init<C, Type, TAG> make_value(Type val) { return val; } FMT_CONSTEXPR init<C, Type, TAG> make_value(Type val) { \
return val; \
}
FMT_MAKE_VALUE(bool_type, bool, int) FMT_MAKE_VALUE(bool_type, bool, int)
FMT_MAKE_VALUE(int_type, short, int) FMT_MAKE_VALUE(int_type, short, int)
@ -661,12 +679,12 @@ FMT_MAKE_VALUE_SAME(uint_type, unsigned)
// either to int or to long long depending on its size. // either to int or to long long depending on its size.
typedef std::conditional<sizeof(long) == sizeof(int), int, long long>::type typedef std::conditional<sizeof(long) == sizeof(int), int, long long>::type
long_type; long_type;
FMT_MAKE_VALUE( FMT_MAKE_VALUE((sizeof(long) == sizeof(int) ? int_type : long_long_type), long,
(sizeof(long) == sizeof(int) ? int_type : long_long_type), long, long_type) long_type)
typedef std::conditional<sizeof(unsigned long) == sizeof(unsigned), typedef std::conditional<sizeof(unsigned long) == sizeof(unsigned), unsigned,
unsigned, unsigned long long>::type ulong_type; unsigned long long>::type ulong_type;
FMT_MAKE_VALUE( FMT_MAKE_VALUE((sizeof(unsigned long) == sizeof(unsigned) ? uint_type
(sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type), : ulong_long_type),
unsigned long, ulong_type) unsigned long, ulong_type)
FMT_MAKE_VALUE_SAME(long_long_type, long long) FMT_MAKE_VALUE_SAME(long_long_type, long long)
@ -676,14 +694,20 @@ FMT_MAKE_VALUE(uint_type, unsigned char, unsigned)
// This doesn't use FMT_MAKE_VALUE because of ambiguity in gcc 4.4. // This doesn't use FMT_MAKE_VALUE because of ambiguity in gcc 4.4.
template <typename C, typename Char> template <typename C, typename Char>
FMT_CONSTEXPR typename std::enable_if< FMT_CONSTEXPR
std::is_same<typename C::char_type, Char>::value, 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; } init<C, int, char_type>>::type
make_value(Char val) {
return val;
}
template <typename C> template <typename C>
FMT_CONSTEXPR typename std::enable_if< FMT_CONSTEXPR
!std::is_same<typename C::char_type, char>::value, 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; } init<C, int, char_type>>::type
make_value(char val) {
return val;
}
FMT_MAKE_VALUE(double_type, float, double) FMT_MAKE_VALUE(double_type, float, double)
FMT_MAKE_VALUE_SAME(double_type, double) FMT_MAKE_VALUE_SAME(double_type, double)
@ -724,17 +748,22 @@ typename std::enable_if<!std::is_same<T, typename C::char_type>::value>::type
} }
template <typename C, typename T> template <typename C, typename T>
inline typename std::enable_if< inline
std::is_enum<T>::value && convert_to_int<T, typename C::char_type>::value, typename std::enable_if<std::is_enum<T>::value &&
convert_to_int<T, typename C::char_type>::value,
init<C, int, int_type>>::type init<C, int, int_type>>::type
make_value(const T &val) { return static_cast<int>(val); } make_value(const T& val) {
return static_cast<int>(val);
}
template <typename C, typename T, typename Char = typename C::char_type> template <typename C, typename T, typename Char = typename C::char_type>
inline typename std::enable_if< inline typename std::enable_if<
is_constructible<basic_string_view<Char>, T>::value && is_constructible<basic_string_view<Char>, T>::value &&
!internal::is_string<T>::value, !internal::is_string<T>::value,
init<C, basic_string_view<Char>, string_type>>::type init<C, basic_string_view<Char>, string_type>>::type
make_value(const T &val) { return basic_string_view<Char>(val); } make_value(const T& val) {
return basic_string_view<Char>(val);
}
template <typename C, typename T, typename Char = typename C::char_type> template <typename C, typename T, typename Char = typename C::char_type>
inline typename std::enable_if< inline typename std::enable_if<
@ -745,11 +774,13 @@ inline typename std::enable_if<
// Implicit conversion to std::string is not handled here because it's // Implicit conversion to std::string is not handled here because it's
// unsafe: https://github.com/fmtlib/fmt/issues/729 // unsafe: https://github.com/fmtlib/fmt/issues/729
init<C, const T&, custom_type>>::type init<C, const T&, custom_type>>::type
make_value(const T &val) { return val; } make_value(const T& val) {
return val;
}
template <typename C, typename T> template <typename C, typename T>
init<C, const void*, named_arg_type> init<C, const void*, named_arg_type> make_value(
make_value(const named_arg<T, typename C::char_type> &val) { const named_arg<T, typename C::char_type>& val) {
basic_format_arg<C> arg = make_arg<C>(val.value); basic_format_arg<C> arg = make_arg<C>(val.value);
std::memcpy(val.data, &arg, sizeof(arg)); std::memcpy(val.data, &arg, sizeof(arg));
return static_cast<const void*>(&val); return static_cast<const void*>(&val);
@ -761,8 +792,8 @@ FMT_CONSTEXPR11 typename std::enable_if<
init<C, basic_string_view<typename C::char_type>, string_type>>::type init<C, basic_string_view<typename C::char_type>, string_type>>::type
make_value(const S& val) { make_value(const S& val) {
// Handle adapted strings. // Handle adapted strings.
static_assert(std::is_same< static_assert(std::is_same<typename C::char_type,
typename C::char_type, typename internal::char_t<S>::type>::value, typename internal::char_t<S>::type>::value,
"mismatch between char-types of context and argument"); "mismatch between char-types of context and argument");
return to_string_view(val); return to_string_view(val);
} }
@ -771,21 +802,19 @@ FMT_CONSTEXPR11 typename std::enable_if<
enum { max_packed_args = 15 }; enum { max_packed_args = 15 };
enum : unsigned long long { is_unpacked_bit = 1ull << 63 }; enum : unsigned long long { is_unpacked_bit = 1ull << 63 };
template <typename Context> template <typename Context> class arg_map;
class arg_map;
} // namespace internal } // namespace internal
// A formatting argument. It is a trivially copyable/constructible type to // A formatting argument. It is a trivially copyable/constructible type to
// allow storage in basic_memory_buffer. // allow storage in basic_memory_buffer.
template <typename Context> template <typename Context> class basic_format_arg {
class basic_format_arg {
private: private:
internal::value<Context> value_; internal::value<Context> value_;
internal::type type_; internal::type type_;
template <typename ContextType, typename T> template <typename ContextType, typename T>
friend FMT_CONSTEXPR basic_format_arg<ContextType> friend FMT_CONSTEXPR basic_format_arg<ContextType> internal::make_arg(
internal::make_arg(const T &value); const T& value);
template <typename Visitor, typename Ctx> template <typename Visitor, typename Ctx>
friend FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type friend FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
@ -829,8 +858,8 @@ struct monostate {};
\endrst \endrst
*/ */
template <typename Visitor, typename Context> template <typename Visitor, typename Context>
FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type visit_format_arg(
visit_format_arg(Visitor &&vis, const basic_format_arg<Context> &arg) { Visitor&& vis, const basic_format_arg<Context>& arg) {
typedef typename Context::char_type char_type; typedef typename Context::char_type char_type;
switch (arg.type_) { switch (arg.type_) {
case internal::none_type: case internal::none_type:
@ -857,8 +886,8 @@ FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
case internal::cstring_type: case internal::cstring_type:
return vis(arg.value_.string.value); return vis(arg.value_.string.value);
case internal::string_type: case internal::string_type:
return vis(basic_string_view<char_type>( return vis(basic_string_view<char_type>(arg.value_.string.value,
arg.value_.string.value, arg.value_.string.size)); arg.value_.string.size));
case internal::pointer_type: case internal::pointer_type:
return vis(arg.value_.pointer); return vis(arg.value_.pointer);
case internal::custom_type: case internal::custom_type:
@ -869,8 +898,8 @@ FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
// DEPRECATED! // DEPRECATED!
template <typename Visitor, typename Context> template <typename Visitor, typename Context>
FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type visit(
visit(Visitor &&vis, const basic_format_arg<Context> &arg) { Visitor&& vis, const basic_format_arg<Context>& arg) {
return visit_format_arg(std::forward<Visitor>(vis), arg); return visit_format_arg(std::forward<Visitor>(vis), arg);
} }
@ -886,8 +915,8 @@ class basic_parse_context : private ErrorHandler {
typedef Char char_type; typedef Char char_type;
typedef typename basic_string_view<Char>::iterator iterator; typedef typename basic_string_view<Char>::iterator iterator;
explicit FMT_CONSTEXPR basic_parse_context( explicit FMT_CONSTEXPR basic_parse_context(basic_string_view<Char> format_str,
basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler()) ErrorHandler eh = ErrorHandler())
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {} : ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}
// Returns an iterator to the beginning of the format string range being // Returns an iterator to the beginning of the format string range being
@ -934,8 +963,7 @@ typedef basic_parse_context<wchar_t> wparse_context;
namespace internal { namespace internal {
// A map from argument names to their values for named arguments. // A map from argument names to their values for named arguments.
template <typename Context> template <typename Context> class arg_map {
class arg_map {
private: private:
arg_map(const arg_map&) = delete; arg_map(const arg_map&) = delete;
void operator=(const arg_map&) = delete; void operator=(const arg_map&) = delete;
@ -964,8 +992,7 @@ class arg_map {
basic_format_arg<Context> find(basic_string_view<char_type> name) const { basic_format_arg<Context> find(basic_string_view<char_type> name) const {
// The list is unsorted, so just return the first matching name. // The list is unsorted, so just return the first matching name.
for (entry *it = map_, *end = map_ + size_; it != end; ++it) { for (entry *it = map_, *end = map_ + size_; it != end; ++it) {
if (it->name == name) if (it->name == name) return it->arg;
return it->arg;
} }
return {}; return {};
} }
@ -980,11 +1007,9 @@ class locale_ref {
public: public:
locale_ref() : locale_(FMT_NULL) {} locale_ref() : locale_(FMT_NULL) {}
template <typename Locale> template <typename Locale> explicit locale_ref(const Locale& loc);
explicit locale_ref(const Locale &loc);
template <typename Locale> template <typename Locale> Locale get() const;
Locale get() const;
}; };
template <typename OutputIt, typename Context, typename Char> template <typename OutputIt, typename Context, typename Char>
@ -1010,16 +1035,15 @@ class context_base {
// Returns the argument with specified index. // Returns the argument with specified index.
format_arg do_get_arg(unsigned arg_id) { format_arg do_get_arg(unsigned arg_id) {
format_arg arg = args_.get(arg_id); format_arg arg = args_.get(arg_id);
if (!arg) if (!arg) parse_context_.on_error("argument index out of range");
parse_context_.on_error("argument index out of range");
return arg; return arg;
} }
// Checks if manual indexing is used and returns the argument with // Checks if manual indexing is used and returns the argument with
// specified index. // specified index.
format_arg get_arg(unsigned arg_id) { format_arg get_arg(unsigned arg_id) {
return this->parse_context().check_arg_id(arg_id) ? return this->parse_context().check_arg_id(arg_id) ? this->do_get_arg(arg_id)
this->do_get_arg(arg_id) : format_arg(); : format_arg();
} }
public: public:
@ -1043,15 +1067,15 @@ class context_base {
locale_ref locale() { return loc_; } locale_ref locale() { return loc_; }
}; };
template <typename Context, typename T> template <typename Context, typename T> struct get_type {
struct get_type { typedef decltype(
typedef decltype(make_value<Context>( make_value<Context>(declval<typename std::decay<T>::type&>())) value_type;
declval<typename std::decay<T>::type&>())) value_type;
static const type value = value_type::type_tag; static const type value = value_type::type_tag;
}; };
template <typename Context> template <typename Context> FMT_CONSTEXPR11 unsigned long long get_types() {
FMT_CONSTEXPR11 unsigned long long get_types() { return 0; } return 0;
}
template <typename Context, typename Arg, typename... Args> template <typename Context, typename Arg, typename... Args>
FMT_CONSTEXPR11 unsigned long long get_types() { FMT_CONSTEXPR11 unsigned long long get_types() {
@ -1067,8 +1091,8 @@ FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value) {
} }
template <bool IS_PACKED, typename Context, typename T> template <bool IS_PACKED, typename Context, typename T>
inline typename std::enable_if<IS_PACKED, value<Context>>::type inline typename std::enable_if<IS_PACKED, value<Context>>::type make_arg(
make_arg(const T &value) { const T& value) {
return make_value<Context>(value); return make_value<Context>(value);
} }
@ -1081,16 +1105,17 @@ inline typename std::enable_if<!IS_PACKED, basic_format_arg<Context>>::type
// Formatting context. // Formatting context.
template <typename OutputIt, typename Char> template <typename OutputIt, typename Char>
class basic_format_context : class basic_format_context
public internal::context_base< : public internal::context_base<
OutputIt, basic_format_context<OutputIt, Char>, Char> { OutputIt, basic_format_context<OutputIt, Char>, Char> {
public: public:
/** The character type for the output. */ /** The character type for the output. */
typedef Char char_type; typedef Char char_type;
// using formatter_type = formatter<T, char_type>; // using formatter_type = formatter<T, char_type>;
template <typename T> template <typename T> struct formatter_type {
struct formatter_type { typedef formatter<T, char_type> type; }; typedef formatter<T, char_type> type;
};
private: private:
internal::arg_map<basic_format_context> map_; internal::arg_map<basic_format_context> map_;
@ -1124,10 +1149,10 @@ class basic_format_context :
format_arg get_arg(basic_string_view<char_type> name); format_arg get_arg(basic_string_view<char_type> name);
}; };
template <typename Char> template <typename Char> struct buffer_context {
struct buffer_context {
typedef basic_format_context< typedef basic_format_context<
std::back_insert_iterator<internal::basic_buffer<Char>>, Char> type; std::back_insert_iterator<internal::basic_buffer<Char>>, Char>
type;
}; };
typedef buffer_context<char>::type format_context; typedef buffer_context<char>::type format_context;
typedef buffer_context<wchar_t>::type wformat_context; typedef buffer_context<wchar_t>::type wformat_context;
@ -1139,16 +1164,15 @@ typedef buffer_context<wchar_t>::type wformat_context;
such as `~fmt::vformat`. such as `~fmt::vformat`.
\endrst \endrst
*/ */
template <typename Context, typename ...Args> template <typename Context, typename... Args> class format_arg_store {
class format_arg_store {
private: private:
static const size_t NUM_ARGS = sizeof...(Args); static const size_t NUM_ARGS = sizeof...(Args);
// Packed is a macro on MinGW so use IS_PACKED instead. // Packed is a macro on MinGW so use IS_PACKED instead.
static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args; static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args;
typedef typename std::conditional<IS_PACKED, typedef typename std::conditional<IS_PACKED, internal::value<Context>,
internal::value<Context>, basic_format_arg<Context>>::type value_type; basic_format_arg<Context>>::type value_type;
// If the arguments are not packed, add one more element to mark the end. // If the arguments are not packed, add one more element to mark the end.
static const size_t DATA_SIZE = static const size_t DATA_SIZE =
@ -1158,9 +1182,8 @@ class format_arg_store {
friend class basic_format_args<Context>; friend class basic_format_args<Context>;
static FMT_CONSTEXPR11 unsigned long long get_types() { static FMT_CONSTEXPR11 unsigned long long get_types() {
return IS_PACKED ? return IS_PACKED ? internal::get_types<Context, Args...>()
internal::get_types<Context, Args...>() : : internal::is_unpacked_bit | NUM_ARGS;
internal::is_unpacked_bit | NUM_ARGS;
} }
public: public:
@ -1174,8 +1197,8 @@ class format_arg_store {
(FMT_MSC_VER && FMT_MSC_VER <= 1800) (FMT_MSC_VER && FMT_MSC_VER <= 1800)
// Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013. // Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013.
format_arg_store(const Args&... args) { format_arg_store(const Args&... args) {
value_type init[DATA_SIZE] = value_type init[DATA_SIZE] = {
{internal::make_arg<IS_PACKED, Context>(args)...}; internal::make_arg<IS_PACKED, Context>(args)...};
std::memcpy(data_, init, sizeof(init)); std::memcpy(data_, init, sizeof(init));
} }
#else #else
@ -1198,12 +1221,13 @@ const unsigned long long format_arg_store<Context, Args...>::TYPES =
\endrst \endrst
*/ */
template <typename Context = format_context, typename... Args> template <typename Context = format_context, typename... Args>
inline format_arg_store<Context, Args...> inline format_arg_store<Context, Args...> make_format_args(
make_format_args(const Args &... args) { return {args...}; } const Args&... args) {
return {args...};
}
/** Formatting arguments. */ /** Formatting arguments. */
template <typename Context> template <typename Context> class basic_format_args {
class basic_format_args {
public: public:
typedef unsigned size_type; typedef unsigned size_type;
typedef basic_format_arg<Context> format_arg; typedef basic_format_arg<Context> format_arg;
@ -1226,8 +1250,8 @@ class basic_format_args {
typename internal::type type(unsigned index) const { typename internal::type type(unsigned index) const {
unsigned shift = index * 4; unsigned shift = index * 4;
return static_cast<typename internal::type>( return static_cast<typename internal::type>((types_ & (0xfull << shift)) >>
(types_ & (0xfull << shift)) >> shift); shift);
} }
friend class internal::arg_map<Context>; friend class internal::arg_map<Context>;
@ -1239,15 +1263,12 @@ class basic_format_args {
format_arg arg; format_arg arg;
if (!is_packed()) { if (!is_packed()) {
auto num_args = max_size(); auto num_args = max_size();
if (index < num_args) if (index < num_args) arg = args_[index];
arg = args_[index];
return arg; return arg;
} }
if (index > internal::max_packed_args) if (index > internal::max_packed_args) return arg;
return arg;
arg.type_ = type(index); arg.type_ = type(index);
if (arg.type_ == internal::none_type) if (arg.type_ == internal::none_type) return arg;
return arg;
internal::value<Context>& val = arg.value_; internal::value<Context>& val = arg.value_;
val = values_[index]; val = values_[index];
return arg; return arg;
@ -1313,37 +1334,34 @@ struct wformat_args : basic_format_args<wformat_context> {
#if FMT_USE_ALIAS_TEMPLATES #if FMT_USE_ALIAS_TEMPLATES
/** String's character type. */ /** String's character type. */
template <typename S> template <typename S>
using char_t = FMT_ENABLE_IF_T( using char_t = FMT_ENABLE_IF_T(internal::is_string<S>::value,
internal::is_string<S>::value, typename internal::char_t<S>::type); typename internal::char_t<S>::type);
# define FMT_CHAR(S) fmt::char_t<S> # define FMT_CHAR(S) fmt::char_t<S>
#else #else
template <typename S> template <typename S>
struct char_t : std::enable_if< struct char_t : std::enable_if<internal::is_string<S>::value,
internal::is_string<S>::value, typename internal::char_t<S>::type> {}; typename internal::char_t<S>::type> {};
# define FMT_CHAR(S) typename char_t<S>::type # define FMT_CHAR(S) typename char_t<S>::type
#endif #endif
namespace internal { namespace internal {
template <typename Char> template <typename Char> struct named_arg_base {
struct named_arg_base {
basic_string_view<Char> name; basic_string_view<Char> name;
// Serialized value<context>. // Serialized value<context>.
mutable char data[ mutable char
sizeof(basic_format_arg<typename buffer_context<Char>::type>)]; data[sizeof(basic_format_arg<typename buffer_context<Char>::type>)];
named_arg_base(basic_string_view<Char> nm) : name(nm) {} named_arg_base(basic_string_view<Char> nm) : name(nm) {}
template <typename Context> template <typename Context> basic_format_arg<Context> deserialize() const {
basic_format_arg<Context> deserialize() const {
basic_format_arg<Context> arg; basic_format_arg<Context> arg;
std::memcpy(&arg, data, sizeof(basic_format_arg<Context>)); std::memcpy(&arg, data, sizeof(basic_format_arg<Context>));
return arg; return arg;
} }
}; };
template <typename T, typename Char> template <typename T, typename Char> struct named_arg : named_arg_base<Char> {
struct named_arg : named_arg_base<Char> {
const T& value; const T& value;
named_arg(basic_string_view<Char> name, const T& val) named_arg(basic_string_view<Char> name, const T& val)
@ -1354,16 +1372,16 @@ template <typename... Args, typename S>
inline typename std::enable_if<!is_compile_string<S>::value>::type inline typename std::enable_if<!is_compile_string<S>::value>::type
check_format_string(const S&) {} check_format_string(const S&) {}
template <typename... Args, typename S> template <typename... Args, typename S>
typename std::enable_if<is_compile_string<S>::value>::type typename std::enable_if<is_compile_string<S>::value>::type check_format_string(
check_format_string(S); S);
template <typename S, typename... Args> template <typename S, typename... Args>
struct checked_args : format_arg_store< struct checked_args
typename buffer_context<FMT_CHAR(S)>::type, Args...> { : format_arg_store<typename buffer_context<FMT_CHAR(S)>::type, Args...> {
typedef typename buffer_context<FMT_CHAR(S)>::type context; typedef typename buffer_context<FMT_CHAR(S)>::type context;
checked_args(const S &format_str, const Args &... args): checked_args(const S& format_str, const Args&... args)
format_arg_store<context, Args...>(args...) { : format_arg_store<context, Args...>(args...) {
internal::check_format_string<Args...>(format_str); internal::check_format_string<Args...>(format_str);
} }
@ -1379,7 +1397,7 @@ template <typename Char>
typename buffer_context<Char>::type::iterator vformat_to( 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); basic_format_args<typename buffer_context<Char>::type> args);
} } // namespace internal
/** /**
\rst \rst
@ -1404,8 +1422,7 @@ inline internal::named_arg<T, wchar_t> arg(wstring_view name, const T &arg) {
template <typename S, typename T, typename Char> template <typename S, typename T, typename Char>
void arg(S, internal::named_arg<T, Char>) = delete; void arg(S, internal::named_arg<T, Char>) = delete;
template <typename Container> template <typename Container> struct is_contiguous : std::false_type {};
struct is_contiguous: std::false_type {};
template <typename Char> template <typename Char>
struct is_contiguous<std::basic_string<Char>> : std::true_type {}; struct is_contiguous<std::basic_string<Char>> : std::true_type {};
@ -1415,11 +1432,9 @@ struct is_contiguous<internal::basic_buffer<Char> >: std::true_type {};
/** Formats a string and writes the output to ``out``. */ /** Formats a string and writes the output to ``out``. */
template <typename Container, typename S> template <typename Container, typename S>
typename std::enable_if< typename std::enable_if<is_contiguous<Container>::value,
is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type std::back_insert_iterator<Container>>::type
vformat_to( vformat_to(std::back_insert_iterator<Container> out, const S& format_str,
std::back_insert_iterator<Container> out,
const S &format_str,
basic_format_args<typename buffer_context<FMT_CHAR(S)>::type> args) { basic_format_args<typename buffer_context<FMT_CHAR(S)>::type> args) {
internal::container_buffer<Container> buf(internal::get_container(out)); internal::container_buffer<Container> buf(internal::get_container(out));
internal::vformat_to(buf, to_string_view(format_str), args); internal::vformat_to(buf, to_string_view(format_str), args);
@ -1427,8 +1442,8 @@ typename std::enable_if<
} }
template <typename Container, typename S, typename... Args> template <typename Container, typename S, typename... Args>
inline typename std::enable_if< inline typename std::enable_if<is_contiguous<Container>::value &&
is_contiguous<Container>::value && internal::is_string<S>::value, internal::is_string<S>::value,
std::back_insert_iterator<Container>>::type std::back_insert_iterator<Container>>::type
format_to(std::back_insert_iterator<Container> out, const S& format_str, format_to(std::back_insert_iterator<Container> out, const S& format_str,
const Args&... args) { const Args&... args) {
@ -1454,8 +1469,8 @@ inline std::basic_string<Char> vformat(
\endrst \endrst
*/ */
template <typename S, typename... Args> template <typename S, typename... Args>
inline std::basic_string<FMT_CHAR(S)> format( inline std::basic_string<FMT_CHAR(S)> format(const S& format_str,
const S &format_str, const Args &... args) { const Args&... args) {
return internal::vformat( return internal::vformat(
to_string_view(format_str), to_string_view(format_str),
*internal::checked_args<S, Args...>(format_str, args...)); *internal::checked_args<S, Args...>(format_str, args...));

View File

@ -96,8 +96,8 @@ typedef void (*FormatFunc)(internal::buffer &, int, string_view);
// ERANGE - buffer is not large enough to store the error message // ERANGE - buffer is not large enough to store the error message
// other - failure // other - failure
// Buffer should be at least of size 1. // Buffer should be at least of size 1.
int safe_strerror( int safe_strerror(int error_code, char*& buffer,
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { std::size_t buffer_size) FMT_NOEXCEPT {
FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer"); FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
class dispatcher { class dispatcher {
@ -132,8 +132,8 @@ int safe_strerror(
// Fallback to strerror_s when strerror_r is not available. // Fallback to strerror_s when strerror_r is not available.
int fallback(int result) { int fallback(int result) {
// If the buffer is full then the message is probably truncated. // If the buffer is full then the message is probably truncated.
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? ERANGE
ERANGE : result; : result;
} }
#if !FMT_MSC_VER #if !FMT_MSC_VER
@ -149,9 +149,7 @@ int safe_strerror(
dispatcher(int err_code, char*& buf, std::size_t buf_size) dispatcher(int err_code, char*& buf, std::size_t buf_size)
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
int run() { int run() { return handle(strerror_r(error_code_, buffer_, buffer_size_)); }
return handle(strerror_r(error_code_, buffer_, buffer_size_));
}
}; };
return dispatcher(error_code, buffer, buffer_size).run(); return dispatcher(error_code, buffer, buffer_size).run();
} }
@ -198,8 +196,7 @@ FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
const char8_t* data = s.data(); const char8_t* data = s.data();
size_t num_code_points = 0; size_t num_code_points = 0;
for (size_t i = 0, size = s.size(); i != size; ++i) { for (size_t i = 0, size = s.size(); i != size; ++i) {
if ((data[i] & 0xc0) != 0x80) if ((data[i] & 0xc0) != 0x80) ++num_code_points;
++num_code_points;
} }
return num_code_points; return num_code_points;
} }
@ -212,18 +209,16 @@ locale_ref::locale_ref(const Locale &loc) : locale_(&loc) {
static_assert(std::is_same<Locale, std::locale>::value, ""); static_assert(std::is_same<Locale, std::locale>::value, "");
} }
template <typename Locale> template <typename Locale> Locale locale_ref::get() const {
Locale locale_ref::get() const {
static_assert(std::is_same<Locale, std::locale>::value, ""); static_assert(std::is_same<Locale, std::locale>::value, "");
return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale(); return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
} }
template <typename Char> template <typename Char> FMT_FUNC Char thousands_sep_impl(locale_ref loc) {
FMT_FUNC Char thousands_sep_impl(locale_ref loc) { return std::use_facet<std::numpunct<Char> >(loc.get<std::locale>())
return std::use_facet<std::numpunct<Char> >( .thousands_sep();
loc.get<std::locale>()).thousands_sep();
}
} }
} // namespace internal
#else #else
template <typename Char> template <typename Char>
FMT_FUNC Char internal::thousands_sep_impl(locale_ref) { FMT_FUNC Char internal::thousands_sep_impl(locale_ref) {
@ -231,8 +226,8 @@ FMT_FUNC Char internal::thousands_sep_impl(locale_ref) {
} }
#endif #endif
FMT_FUNC void system_error::init( FMT_FUNC void system_error::init(int err_code, string_view format_str,
int err_code, string_view format_str, format_args args) { format_args args) {
error_code_ = err_code; error_code_ = err_code;
memory_buffer buffer; memory_buffer buffer;
format_system_error(buffer, err_code, vformat(format_str, args)); format_system_error(buffer, err_code, vformat(format_str, args));
@ -242,20 +237,19 @@ FMT_FUNC void system_error::init(
namespace internal { namespace internal {
template <typename T> template <typename T>
int char_traits<char>::format_float( int char_traits<char>::format_float(char* buf, std::size_t size,
char *buf, std::size_t size, const char *format, int precision, T value) { const char* format, int precision,
return precision < 0 ? T value) {
FMT_SNPRINTF(buf, size, format, value) : return precision < 0 ? FMT_SNPRINTF(buf, size, format, value)
FMT_SNPRINTF(buf, size, format, precision, value); : FMT_SNPRINTF(buf, size, format, precision, value);
} }
template <typename T> template <typename T>
int char_traits<wchar_t>::format_float( int char_traits<wchar_t>::format_float(wchar_t* buf, std::size_t size,
wchar_t *buf, std::size_t size, const wchar_t *format, int precision, const wchar_t* format, int precision,
T value) { T value) {
return precision < 0 ? return precision < 0 ? FMT_SWPRINTF(buf, size, format, value)
FMT_SWPRINTF(buf, size, format, value) : : FMT_SWPRINTF(buf, size, format, precision, value);
FMT_SWPRINTF(buf, size, format, precision, value);
} }
template <typename T> template <typename T>
@ -267,33 +261,21 @@ const char basic_data<T>::DIGITS[] =
"8081828384858687888990919293949596979899"; "8081828384858687888990919293949596979899";
#define FMT_POWERS_OF_10(factor) \ #define FMT_POWERS_OF_10(factor) \
factor * 10, \ factor * 10, factor * 100, factor * 1000, factor * 10000, factor * 100000, \
factor * 100, \ factor * 1000000, factor * 10000000, factor * 100000000, \
factor * 1000, \
factor * 10000, \
factor * 100000, \
factor * 1000000, \
factor * 10000000, \
factor * 100000000, \
factor * 1000000000 factor * 1000000000
template <typename T> template <typename T>
const uint32_t basic_data<T>::POWERS_OF_10_32[] = { const uint32_t basic_data<T>::POWERS_OF_10_32[] = {1, FMT_POWERS_OF_10(1)};
1, FMT_POWERS_OF_10(1)
};
template <typename T> template <typename T>
const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = { const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {0,
0, FMT_POWERS_OF_10(1) FMT_POWERS_OF_10(1)};
};
template <typename T> template <typename T>
const uint64_t basic_data<T>::ZERO_OR_POWERS_OF_10_64[] = { const uint64_t basic_data<T>::ZERO_OR_POWERS_OF_10_64[] = {
0, 0, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(1000000000ull),
FMT_POWERS_OF_10(1), 10000000000000000000ull};
FMT_POWERS_OF_10(1000000000ull),
10000000000000000000ull
};
// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. // Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
// These are generated by support/compute-powers.py. // These are generated by support/compute-powers.py.
@ -341,11 +323,12 @@ const int16_t basic_data<T>::POW10_EXPONENTS[] = {
-50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216,
242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508,
534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800,
827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066};
};
template <typename T> const char basic_data<T>::FOREGROUND_COLOR[] = "\x1b[38;2;"; template <typename T>
template <typename T> const char basic_data<T>::BACKGROUND_COLOR[] = "\x1b[48;2;"; const char basic_data<T>::FOREGROUND_COLOR[] = "\x1b[38;2;";
template <typename T>
const char basic_data<T>::BACKGROUND_COLOR[] = "\x1b[48;2;";
template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m"; template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m"; template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
@ -376,8 +359,7 @@ class fp {
// Constructs fp from an IEEE754 double. It is a template to prevent compile // Constructs fp from an IEEE754 double. It is a template to prevent compile
// errors on platforms where double is not IEEE754. // errors on platforms where double is not IEEE754.
template <typename Double> template <typename Double> explicit fp(Double d) {
explicit fp(Double d) {
// Assume double is in the format [sign][exponent][significand]. // Assume double is in the format [sign][exponent][significand].
typedef std::numeric_limits<Double> limits; typedef std::numeric_limits<Double> limits;
const int double_size = static_cast<int>(sizeof(Double) * char_size); const int double_size = static_cast<int>(sizeof(Double) * char_size);
@ -397,8 +379,7 @@ class fp {
} }
// Normalizes the value converted from double and multiplied by (1 << SHIFT). // Normalizes the value converted from double and multiplied by (1 << SHIFT).
template <int SHIFT = 0> template <int SHIFT = 0> void normalize() {
void normalize() {
// Handle subnormals. // Handle subnormals.
auto shifted_implicit_bit = implicit_bit << SHIFT; auto shifted_implicit_bit = implicit_bit << SHIFT;
while ((f & shifted_implicit_bit) == 0) { while ((f & shifted_implicit_bit) == 0) {
@ -416,8 +397,8 @@ class fp {
// (lower) or successor (upper). The upper boundary is normalized and lower // (lower) or successor (upper). The upper boundary is normalized and lower
// has the same exponent but may be not normalized. // has the same exponent but may be not normalized.
void compute_boundaries(fp& lower, fp& upper) const { void compute_boundaries(fp& lower, fp& upper) const {
lower = f == implicit_bit ? lower =
fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1); f == implicit_bit ? fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1);
upper = fp((f << 1) + 1, e - 1); upper = fp((f << 1) + 1, e - 1);
upper.normalize<1>(); // 1 is to account for the exponent shift above. upper.normalize<1>(); // 1 is to account for the exponent shift above.
lower.f <<= lower.e - upper.e; lower.f <<= lower.e - upper.e;
@ -432,7 +413,8 @@ inline fp operator-(fp x, fp y) {
} }
// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest // Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest
// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized. // with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be
// normalized.
FMT_API fp operator*(fp x, fp y); FMT_API fp operator*(fp x, fp y);
// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its // Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
@ -452,8 +434,8 @@ FMT_FUNC fp operator*(fp x, fp y) {
FMT_FUNC fp get_cached_power(int min_exponent, int& pow10_exponent) { FMT_FUNC fp get_cached_power(int min_exponent, int& pow10_exponent) {
const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10) const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
int index = static_cast<int>(std::ceil( int index = static_cast<int>(
(min_exponent + fp::significand_size - 1) * one_over_log2_10)); std::ceil((min_exponent + fp::significand_size - 1) * one_over_log2_10));
// Decimal exponent of the first (smallest) cached power of 10. // Decimal exponent of the first (smallest) cached power of 10.
const int first_dec_exp = -348; const int first_dec_exp = -348;
// Difference between 2 consecutive decimal exponents in cached powers of 10. // Difference between 2 consecutive decimal exponents in cached powers of 10.
@ -463,10 +445,11 @@ FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]); return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
} }
FMT_FUNC bool grisu2_round( FMT_FUNC bool grisu2_round(char* buf, int& size, int max_digits, uint64_t delta,
char *buf, int &size, int max_digits, uint64_t delta, uint64_t remainder, uint64_t exp, uint64_t diff,
uint64_t remainder, uint64_t exp, uint64_t diff, int &exp10) { int& exp10) {
while (remainder < diff && delta - remainder >= exp && while (
remainder < diff && delta - remainder >= exp &&
(remainder + exp < diff || diff - remainder > remainder + exp - diff)) { (remainder + exp < diff || diff - remainder > remainder + exp - diff)) {
--buf[size - 1]; --buf[size - 1];
remainder += exp; remainder += exp;
@ -474,44 +457,72 @@ FMT_FUNC bool grisu2_round(
if (size > max_digits) { if (size > max_digits) {
--size; --size;
++exp10; ++exp10;
if (buf[size] >= '5') if (buf[size] >= '5') return false;
return false;
} }
return true; return true;
} }
// Generates output using Grisu2 digit-gen algorithm. // Generates output using Grisu2 digit-gen algorithm.
FMT_FUNC bool grisu2_gen_digits( FMT_FUNC bool grisu2_gen_digits(char* buf, int& size, uint32_t hi, uint64_t lo,
char *buf, int &size, uint32_t hi, uint64_t lo, int &exp, int& exp, uint64_t delta, const fp& one,
uint64_t delta, const fp &one, const fp &diff, int max_digits) { const fp& diff, int max_digits) {
// Generate digits for the most significant part (hi). // Generate digits for the most significant part (hi).
while (exp > 0) { while (exp > 0) {
uint32_t digit = 0; uint32_t digit = 0;
// This optimization by miloyip reduces the number of integer divisions by // This optimization by miloyip reduces the number of integer divisions by
// one per iteration. // one per iteration.
switch (exp) { switch (exp) {
case 10: digit = hi / 1000000000; hi %= 1000000000; break; case 10:
case 9: digit = hi / 100000000; hi %= 100000000; break; digit = hi / 1000000000;
case 8: digit = hi / 10000000; hi %= 10000000; break; hi %= 1000000000;
case 7: digit = hi / 1000000; hi %= 1000000; break; break;
case 6: digit = hi / 100000; hi %= 100000; break; case 9:
case 5: digit = hi / 10000; hi %= 10000; break; digit = hi / 100000000;
case 4: digit = hi / 1000; hi %= 1000; break; hi %= 100000000;
case 3: digit = hi / 100; hi %= 100; break; break;
case 2: digit = hi / 10; hi %= 10; break; case 8:
case 1: digit = hi; hi = 0; break; digit = hi / 10000000;
hi %= 10000000;
break;
case 7:
digit = hi / 1000000;
hi %= 1000000;
break;
case 6:
digit = hi / 100000;
hi %= 100000;
break;
case 5:
digit = hi / 10000;
hi %= 10000;
break;
case 4:
digit = hi / 1000;
hi %= 1000;
break;
case 3:
digit = hi / 100;
hi %= 100;
break;
case 2:
digit = hi / 10;
hi %= 10;
break;
case 1:
digit = hi;
hi = 0;
break;
default: default:
FMT_ASSERT(false, "invalid number of digits"); FMT_ASSERT(false, "invalid number of digits");
} }
if (digit != 0 || size != 0) if (digit != 0 || size != 0) buf[size++] = static_cast<char>('0' + digit);
buf[size++] = static_cast<char>('0' + digit);
--exp; --exp;
uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo; uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
if (remainder <= delta || size > max_digits) { if (remainder <= delta || size > max_digits) {
return grisu2_round( return grisu2_round(
buf, size, max_digits, delta, remainder, buf, size, max_digits, delta, remainder,
static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e, static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e, diff.f,
diff.f, exp); exp);
} }
} }
// Generate digits for the least significant part (lo). // Generate digits for the least significant part (lo).
@ -519,8 +530,7 @@ FMT_FUNC bool grisu2_gen_digits(
lo *= 10; lo *= 10;
delta *= 10; delta *= 10;
char digit = static_cast<char>(lo >> -one.e); char digit = static_cast<char>(lo >> -one.e);
if (digit != 0 || size != 0) if (digit != 0 || size != 0) buf[size++] = static_cast<char>('0' + digit);
buf[size++] = static_cast<char>('0' + digit);
lo &= one.f - 1; lo &= one.f - 1;
--exp; --exp;
if (lo < delta || size > max_digits) { if (lo < delta || size > max_digits) {
@ -557,8 +567,7 @@ struct prettify_handler {
buf.resize(to_unsigned(size)); buf.resize(to_unsigned(size));
} }
template <typename F> template <typename F> void insert(ptrdiff_t pos, ptrdiff_t n, F f) {
void insert(ptrdiff_t pos, ptrdiff_t n, F f) {
std::memmove(data + pos + n, data + pos, to_unsigned(size - pos)); std::memmove(data + pos + n, data + pos, to_unsigned(size - pos));
f(data + pos); f(data + pos);
size += n; size += n;
@ -583,8 +592,7 @@ struct prettify_handler {
}; };
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer. // Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
template <typename Handler> template <typename Handler> FMT_FUNC void write_exponent(int exp, Handler&& h) {
FMT_FUNC void write_exponent(int exp, Handler &&h) {
FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range"); FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
if (exp < 0) { if (exp < 0) {
h.append('-'); h.append('-');
@ -616,14 +624,13 @@ struct fill {
// The number is given as v = f * pow(10, exp), where f has size digits. // The number is given as v = f * pow(10, exp), where f has size digits.
template <typename Handler> template <typename Handler>
FMT_FUNC void grisu2_prettify(const gen_digits_params &params, FMT_FUNC void grisu2_prettify(const gen_digits_params& params, int size,
int size, int exp, Handler &&handler) { int exp, Handler&& handler) {
if (!params.fixed) { if (!params.fixed) {
// Insert a decimal point after the first digit and add an exponent. // Insert a decimal point after the first digit and add an exponent.
handler.insert(1, '.'); handler.insert(1, '.');
exp += size - 1; exp += size - 1;
if (size < params.num_digits) if (size < params.num_digits) handler.append(params.num_digits - size, '0');
handler.append(params.num_digits - size, '0');
handler.append(params.upper ? 'E' : 'e'); handler.append(params.upper ? 'E' : 'e');
write_exponent(exp, handler); write_exponent(exp, handler);
return; return;
@ -659,8 +666,7 @@ FMT_FUNC void grisu2_prettify(const gen_digits_params &params,
struct char_counter { struct char_counter {
ptrdiff_t size; ptrdiff_t size;
template <typename F> template <typename F> void insert(ptrdiff_t, ptrdiff_t n, F) { size += n; }
void insert(ptrdiff_t, ptrdiff_t n, F) { size += n; }
void insert(ptrdiff_t, char) { ++size; } void insert(ptrdiff_t, char) { ++size; }
void append(ptrdiff_t n, char) { size += n; } void append(ptrdiff_t n, char) { size += n; }
void append(char) { ++size; } void append(char) { ++size; }
@ -678,7 +684,8 @@ FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,
case 'G': case 'G':
params.upper = true; params.upper = true;
FMT_FALLTHROUGH FMT_FALLTHROUGH
case '\0': case 'g': case '\0':
case 'g':
params.trailing_zeros = (specs.flags & HASH_FLAG) != 0; params.trailing_zeros = (specs.flags & HASH_FLAG) != 0;
if (-4 <= exp && exp < num_digits + 1) { if (-4 <= exp && exp < num_digits + 1) {
params.fixed = true; params.fixed = true;
@ -693,8 +700,7 @@ FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,
params.fixed = true; params.fixed = true;
params.trailing_zeros = true; params.trailing_zeros = true;
int adjusted_min_digits = num_digits + exp; int adjusted_min_digits = num_digits + exp;
if (adjusted_min_digits > 0) if (adjusted_min_digits > 0) num_digits = adjusted_min_digits;
num_digits = adjusted_min_digits;
break; break;
} }
case 'E': case 'E':
@ -771,14 +777,12 @@ void sprintf_format(Double value, internal::buffer &buf,
char format[MAX_FORMAT_SIZE]; char format[MAX_FORMAT_SIZE];
char* format_ptr = format; char* format_ptr = format;
*format_ptr++ = '%'; *format_ptr++ = '%';
if (spec.has(HASH_FLAG)) if (spec.has(HASH_FLAG)) *format_ptr++ = '#';
*format_ptr++ = '#';
if (spec.precision >= 0) { if (spec.precision >= 0) {
*format_ptr++ = '.'; *format_ptr++ = '.';
*format_ptr++ = '*'; *format_ptr++ = '*';
} }
if (std::is_same<Double, long double>::value) if (std::is_same<Double, long double>::value) *format_ptr++ = 'L';
*format_ptr++ = 'L';
*format_ptr++ = spec.type; *format_ptr++ = spec.type;
*format_ptr = '\0'; *format_ptr = '\0';
@ -819,15 +823,13 @@ FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
return; return;
} }
int length = MultiByteToWideChar( int length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(),
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0); s_size, FMT_NULL, 0);
if (length == 0) if (length == 0) FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
buffer_.resize(length + 1); buffer_.resize(length + 1);
length = MultiByteToWideChar( length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size,
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); &buffer_[0], length);
if (length == 0) if (length == 0) FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
buffer_[length] = 0; buffer_[length] = 0;
} }
@ -839,8 +841,7 @@ FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
} }
FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) { FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
if (s.size() > INT_MAX) if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER;
return ERROR_INVALID_PARAMETER;
int s_size = static_cast<int>(s.size()); int s_size = static_cast<int>(s.size());
if (s_size == 0) { if (s_size == 0) {
// WideCharToMultiByte does not support zero length, handle separately. // WideCharToMultiByte does not support zero length, handle separately.
@ -849,21 +850,19 @@ FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
return 0; return 0;
} }
int length = WideCharToMultiByte( int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0,
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL); FMT_NULL, FMT_NULL);
if (length == 0) if (length == 0) return GetLastError();
return GetLastError();
buffer_.resize(length + 1); buffer_.resize(length + 1);
length = WideCharToMultiByte( length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0],
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL); length, FMT_NULL, FMT_NULL);
if (length == 0) if (length == 0) return GetLastError();
return GetLastError();
buffer_[length] = 0; buffer_[length] = 0;
return 0; return 0;
} }
FMT_FUNC void windows_error::init( FMT_FUNC void windows_error::init(int err_code, string_view format_str,
int err_code, string_view format_str, format_args args) { format_args args) {
error_code_ = err_code; error_code_ = err_code;
memory_buffer buffer; memory_buffer buffer;
internal::format_windows_error(buffer, err_code, vformat(format_str, args)); internal::format_windows_error(buffer, err_code, vformat(format_str, args));
@ -871,17 +870,18 @@ FMT_FUNC void windows_error::init(
base = std::runtime_error(to_string(buffer)); base = std::runtime_error(to_string(buffer));
} }
FMT_FUNC void internal::format_windows_error( FMT_FUNC void internal::format_windows_error(internal::buffer& out,
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT { int error_code,
string_view message) FMT_NOEXCEPT {
FMT_TRY { FMT_TRY {
wmemory_buffer buf; wmemory_buffer buf;
buf.resize(inline_buffer_size); buf.resize(inline_buffer_size);
for (;;) { for (;;) {
wchar_t* system_message = &buf[0]; wchar_t* system_message = &buf[0];
int result = FormatMessageW( int result = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, FMT_NULL,
FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message,
system_message, static_cast<uint32_t>(buf.size()), FMT_NULL); static_cast<uint32_t>(buf.size()), FMT_NULL);
if (result != 0) { if (result != 0) {
utf16_to_utf8 utf8_message; utf16_to_utf8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) { if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
@ -897,14 +897,15 @@ FMT_FUNC void internal::format_windows_error(
break; // Can't get error message, report error code instead. break; // Can't get error message, report error code instead.
buf.resize(buf.size() * 2); buf.resize(buf.size() * 2);
} }
} FMT_CATCH(...) {} }
FMT_CATCH(...) {}
format_error_code(out, error_code, message); format_error_code(out, error_code, message);
} }
#endif // FMT_USE_WINDOWS_H #endif // FMT_USE_WINDOWS_H
FMT_FUNC void format_system_error( FMT_FUNC void format_system_error(internal::buffer& out, int error_code,
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT { string_view message) FMT_NOEXCEPT {
FMT_TRY { FMT_TRY {
memory_buffer buf; memory_buffer buf;
buf.resize(inline_buffer_size); buf.resize(inline_buffer_size);
@ -922,7 +923,8 @@ FMT_FUNC void format_system_error(
break; // Can't get error message, report error code instead. break; // Can't get error message, report error code instead.
buf.resize(buf.size() * 2); buf.resize(buf.size() * 2);
} }
} FMT_CATCH(...) {} }
FMT_CATCH(...) {}
format_error_code(out, error_code, message); format_error_code(out, error_code, message);
} }
@ -930,14 +932,14 @@ FMT_FUNC void internal::error_handler::on_error(const char *message) {
FMT_THROW(format_error(message)); FMT_THROW(format_error(message));
} }
FMT_FUNC void report_system_error( FMT_FUNC void report_system_error(int error_code,
int error_code, fmt::string_view message) FMT_NOEXCEPT { fmt::string_view message) FMT_NOEXCEPT {
report_error(format_system_error, error_code, message); report_error(format_system_error, error_code, message);
} }
#if FMT_USE_WINDOWS_H #if FMT_USE_WINDOWS_H
FMT_FUNC void report_windows_error( FMT_FUNC void report_windows_error(int error_code,
int error_code, fmt::string_view message) FMT_NOEXCEPT { fmt::string_view message) FMT_NOEXCEPT {
report_error(internal::format_windows_error, error_code, message); report_error(internal::format_windows_error, error_code, message);
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -8,8 +8,8 @@
#ifndef FMT_LOCALE_H_ #ifndef FMT_LOCALE_H_
#define FMT_LOCALE_H_ #define FMT_LOCALE_H_
#include "format.h"
#include <locale> #include <locale>
#include "format.h"
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
@ -20,8 +20,8 @@ typename buffer_context<Char>::type::iterator vformat_to(
basic_string_view<Char> format_str, basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> args) { basic_format_args<typename buffer_context<Char>::type> args) {
typedef back_insert_range<basic_buffer<Char>> range; typedef back_insert_range<basic_buffer<Char>> range;
return vformat_to<arg_formatter<range>>( return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str), args,
buf, to_string_view(format_str), args, internal::locale_ref(loc)); internal::locale_ref(loc));
} }
template <typename Char> template <typename Char>
@ -32,7 +32,7 @@ std::basic_string<Char> vformat(
internal::vformat_to(loc, buffer, format_str, args); internal::vformat_to(loc, buffer, format_str, args);
return fmt::to_string(buffer); return fmt::to_string(buffer);
} }
} } // namespace internal
template <typename S, typename Char = FMT_CHAR(S)> template <typename S, typename Char = FMT_CHAR(S)>
inline std::basic_string<Char> vformat( inline std::basic_string<Char> vformat(
@ -42,8 +42,9 @@ inline std::basic_string<Char> vformat(
} }
template <typename S, typename... Args> template <typename S, typename... Args>
inline std::basic_string<FMT_CHAR(S)> format( inline std::basic_string<FMT_CHAR(S)> format(const std::locale& loc,
const std::locale &loc, const S &format_str, const Args &... args) { const S& format_str,
const Args&... args) {
return internal::vformat( return internal::vformat(
loc, to_string_view(format_str), loc, to_string_view(format_str),
*internal::checked_args<S, Args...>(format_str, args...)); *internal::checked_args<S, Args...>(format_str, args...));
@ -60,9 +61,10 @@ inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
} }
template <typename OutputIt, typename S, typename... Args> template <typename OutputIt, typename S, typename... Args>
inline typename std::enable_if< inline
internal::is_string<S>::value && typename std::enable_if<internal::is_string<S>::value &&
internal::is_output_iterator<OutputIt>::value, OutputIt>::type internal::is_output_iterator<OutputIt>::value,
OutputIt>::type
format_to(OutputIt out, const std::locale& loc, const S& format_str, format_to(OutputIt out, const std::locale& loc, const S& format_str,
const Args&... args) { const Args&... args) {
internal::check_format_string<Args...>(format_str); internal::check_format_string<Args...>(format_str);

View File

@ -8,14 +8,13 @@
#ifndef FMT_OSTREAM_H_ #ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_ #define FMT_OSTREAM_H_
#include "format.h"
#include <ostream> #include <ostream>
#include "format.h"
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
namespace internal { namespace internal {
template <class Char> template <class Char> class formatbuf : public std::basic_streambuf<Char> {
class formatbuf : public std::basic_streambuf<Char> {
private: private:
typedef typename std::basic_streambuf<Char>::int_type int_type; typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type; typedef typename std::basic_streambuf<Char>::traits_type traits_type;
@ -45,25 +44,24 @@ class formatbuf : public std::basic_streambuf<Char> {
} }
}; };
template <typename Char> template <typename Char> struct test_stream : std::basic_ostream<Char> {
struct test_stream : std::basic_ostream<Char> {
private: private:
struct null; struct null;
// Hide all operator<< from std::basic_ostream<Char>. // Hide all operator<< from std::basic_ostream<Char>.
void operator<<(null); void operator<<(null);
}; };
// Checks if T has a user-defined operator<< (e.g. not a member of std::ostream). // Checks if T has a user-defined operator<< (e.g. not a member of
template <typename T, typename Char> // std::ostream).
class is_streamable { template <typename T, typename Char> class is_streamable {
private: private:
template <typename U> template <typename U>
static decltype( static decltype(internal::declval<test_stream<Char>&>()
internal::declval<test_stream<Char>&>() << internal::declval<U>(),
<< internal::declval<U>(), std::true_type()) test(int); std::true_type())
test(int);
template <typename> template <typename> static std::false_type test(...);
static std::false_type test(...);
typedef decltype(test<T>(0)) result; typedef decltype(test<T>(0)) result;
@ -99,10 +97,8 @@ void format_value(basic_buffer<Char> &buffer, const T &value) {
// Disable conversion to int if T has an overloaded operator<< which is a free // Disable conversion to int if T has an overloaded operator<< which is a free
// function (not a member of std::ostream). // function (not a member of std::ostream).
template <typename T, typename Char> template <typename T, typename Char> struct convert_to_int<T, Char, void> {
struct convert_to_int<T, Char, void> { static const bool value = convert_to_int<T, Char, int>::value &&
static const bool value =
convert_to_int<T, Char, int>::value &&
!internal::is_streamable<T, Char>::value; !internal::is_streamable<T, Char>::value;
}; };
@ -111,10 +107,9 @@ template <typename T, typename Char>
struct formatter<T, Char, struct formatter<T, Char,
typename std::enable_if< typename std::enable_if<
internal::is_streamable<T, Char>::value && internal::is_streamable<T, Char>::value &&
!internal::format_type< !internal::format_type<typename buffer_context<Char>::type,
typename buffer_context<Char>::type, T>::value>::type> T>::value>::type>
: formatter<basic_string_view<Char>, Char> { : formatter<basic_string_view<Char>, Char> {
template <typename Context> template <typename Context>
auto format(const T& value, Context& ctx) -> decltype(ctx.out()) { auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
basic_memory_buffer<Char> buffer; basic_memory_buffer<Char> buffer;
@ -125,8 +120,8 @@ struct formatter<T, Char,
}; };
template <typename Char> template <typename Char>
inline void vprint(std::basic_ostream<Char> &os, inline void vprint(
basic_string_view<Char> format_str, std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> args) { basic_format_args<typename buffer_context<Char>::type> args) {
basic_memory_buffer<Char> buffer; basic_memory_buffer<Char> buffer;
internal::vformat_to(buffer, format_str, args); internal::vformat_to(buffer, format_str, args);
@ -142,8 +137,8 @@ inline void vprint(std::basic_ostream<Char> &os,
\endrst \endrst
*/ */
template <typename S, typename... Args> template <typename S, typename... Args>
inline typename std::enable_if<internal::is_string<S>::value>::type inline typename std::enable_if<internal::is_string<S>::value>::type print(
print(std::basic_ostream<FMT_CHAR(S)> &os, const S &format_str, std::basic_ostream<FMT_CHAR(S)>& os, const S& format_str,
const Args&... args) { const Args&... args) {
internal::checked_args<S, Args...> ca(format_str, args...); internal::checked_args<S, Args...> ca(format_str, args...);
vprint(os, to_string_view(format_str), *ca); vprint(os, to_string_view(format_str), *ca);

View File

@ -89,8 +89,7 @@ FMT_BEGIN_NAMESPACE
format(std::string("{}"), 42); format(std::string("{}"), 42);
\endrst \endrst
*/ */
template <typename Char> template <typename Char> class basic_cstring_view {
class basic_cstring_view {
private: private:
const Char* data_; const Char* data_;
@ -143,7 +142,6 @@ class buffered_file {
buffered_file(const buffered_file&) = delete; buffered_file(const buffered_file&) = delete;
void operator=(const buffered_file&) = delete; void operator=(const buffered_file&) = delete;
public: public:
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) { buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
other.file_ = FMT_NULL; other.file_ = FMT_NULL;
@ -211,9 +209,7 @@ class file {
void operator=(const file&) = delete; void operator=(const file&) = delete;
public: public:
file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) { file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
other.fd_ = -1;
}
file& operator=(file&& other) { file& operator=(file&& other) {
close(); close();
@ -284,9 +280,7 @@ class Locale {
return _create_locale(category_mask, locale); return _create_locale(category_mask, locale);
} }
static void freelocale(locale_t locale) { static void freelocale(locale_t locale) { _free_locale(locale); }
_free_locale(locale);
}
static double strtod_l(const char* nptr, char** endptr, _locale_t locale) { static double strtod_l(const char* nptr, char** endptr, _locale_t locale) {
return _strtod_l(nptr, endptr, locale); return _strtod_l(nptr, endptr, locale);
@ -302,8 +296,7 @@ class Locale {
typedef locale_t Type; typedef locale_t Type;
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) { Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
if (!locale_) if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
FMT_THROW(system_error(errno, "cannot create locale"));
} }
~Locale() { freelocale(locale_); } ~Locale() { freelocale(locale_); }

View File

@ -73,7 +73,8 @@ template <typename Char> struct format_part {
: which(which_value::argument_id), end_of_argument_id(0u), val(id) {} : which(which_value::argument_id), end_of_argument_id(0u), val(id) {}
FMT_CONSTEXPR format_part(named_argument_id arg_id) FMT_CONSTEXPR format_part(named_argument_id arg_id)
: which(which_value::named_argument_id), end_of_argument_id(0u), : which(which_value::named_argument_id),
end_of_argument_id(0u),
val(arg_id) {} val(arg_id) {}
FMT_CONSTEXPR format_part(specification spec) FMT_CONSTEXPR format_part(specification spec)
@ -99,7 +100,8 @@ template <typename Char> struct format_part {
internal::string_view_metadata named_arg_id; internal::string_view_metadata named_arg_id;
internal::string_view_metadata text; internal::string_view_metadata text;
specification spec; specification spec;
} val; }
val;
}; };
namespace internal { namespace internal {
@ -151,8 +153,7 @@ public:
typedef basic_parse_context<Char> parse_context; typedef basic_parse_context<Char> parse_context;
internal::dynamic_format_specs<Char> parsed_specs; internal::dynamic_format_specs<Char> parsed_specs;
dynamic_specs_handler<parse_context> handler( dynamic_specs_handler<parse_context> handler(parsed_specs, parse_context_);
parsed_specs, parse_context_);
begin = parse_format_specs(begin, end, handler); begin = parse_format_specs(begin, end, handler);
if (*begin != '}') { if (*begin != '}') {
@ -241,9 +242,8 @@ class prepared_format {
} }
template <std::size_t SIZE = inline_buffer_size> template <std::size_t SIZE = inline_buffer_size>
inline typename buffer_context<char_type>::type::iterator inline typename buffer_context<char_type>::type::iterator format_to(
format_to(basic_memory_buffer<char_type, SIZE> &buf, basic_memory_buffer<char_type, SIZE>& buf, const Args&... args) const {
const Args &... args) const {
typedef back_insert_range<internal::basic_buffer<char_type>> range; typedef back_insert_range<internal::basic_buffer<char_type>> range;
return this->vformat_to(range(buf), *checked_args(format_, args...)); return this->vformat_to(range(buf), *checked_args(format_, args...));
} }
@ -322,8 +322,8 @@ class prepared_format {
} }
template <typename Char> template <typename Char>
void check_prepared_specs( void check_prepared_specs(const basic_format_specs<Char>& specs,
const basic_format_specs<Char> &specs, internal::type arg_type) const { internal::type arg_type) const {
internal::error_handler h; internal::error_handler h;
numeric_specs_checker<internal::error_handler> checker(h, arg_type); numeric_specs_checker<internal::error_handler> checker(h, arg_type);
if (specs.align_ == ALIGN_NUMERIC) { if (specs.align_ == ALIGN_NUMERIC) {

View File

@ -18,20 +18,16 @@ namespace internal {
// Checks if a value fits in int - used to avoid warnings about comparing // Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers. // signed and unsigned integers.
template <bool IsSigned> template <bool IsSigned> struct int_checker {
struct int_checker { template <typename T> static bool fits_in_int(T value) {
template <typename T>
static bool fits_in_int(T value) {
unsigned max = std::numeric_limits<int>::max(); unsigned max = std::numeric_limits<int>::max();
return value <= max; return value <= max;
} }
static bool fits_in_int(bool) { return true; } static bool fits_in_int(bool) { return true; }
}; };
template <> template <> struct int_checker<true> {
struct int_checker<true> { template <typename T> static bool fits_in_int(T value) {
template <typename T>
static bool fits_in_int(T value) {
return value >= std::numeric_limits<int>::min() && return value >= std::numeric_limits<int>::min() &&
value <= std::numeric_limits<int>::max(); value <= std::numeric_limits<int>::max();
} }
@ -41,15 +37,16 @@ struct int_checker<true> {
class printf_precision_handler : public function<int> { class printf_precision_handler : public function<int> {
public: public:
template <typename T> template <typename T>
typename std::enable_if<std::is_integral<T>::value, int>::type typename std::enable_if<std::is_integral<T>::value, int>::type operator()(
operator()(T value) { T value) {
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(format_error("number is too big")); FMT_THROW(format_error("number is too big"));
return static_cast<int>(value); return static_cast<int>(value);
} }
template <typename T> template <typename T>
typename std::enable_if<!std::is_integral<T>::value, int>::type operator()(T) { typename std::enable_if<!std::is_integral<T>::value, int>::type operator()(
T) {
FMT_THROW(format_error("precision is not integer")); FMT_THROW(format_error("precision is not integer"));
return 0; return 0;
} }
@ -59,21 +56,21 @@ class printf_precision_handler: public function<int> {
class is_zero_int : public function<bool> { class is_zero_int : public function<bool> {
public: public:
template <typename T> template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type typename std::enable_if<std::is_integral<T>::value, bool>::type operator()(
operator()(T value) { return value == 0; } T value) {
return value == 0;
}
template <typename T> template <typename T>
typename std::enable_if<!std::is_integral<T>::value, bool>::type typename std::enable_if<!std::is_integral<T>::value, bool>::type operator()(
operator()(T) { return false; } T) {
return false;
}
}; };
template <typename T> template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {};
struct make_unsigned_or_bool : std::make_unsigned<T> {};
template <> template <> struct make_unsigned_or_bool<bool> { typedef bool type; };
struct make_unsigned_or_bool<bool> {
typedef bool type;
};
template <typename T, typename Context> template <typename T, typename Context>
class arg_converter : public function<void> { class arg_converter : public function<void> {
@ -88,16 +85,15 @@ class arg_converter: public function<void> {
: arg_(arg), type_(type) {} : arg_(arg), type_(type) {}
void operator()(bool value) { void operator()(bool value) {
if (type_ != 's') if (type_ != 's') operator()<bool>(value);
operator()<bool>(value);
} }
template <typename U> template <typename U>
typename std::enable_if<std::is_integral<U>::value>::type typename std::enable_if<std::is_integral<U>::value>::type operator()(
operator()(U value) { U value) {
bool is_signed = type_ == 'd' || type_ == 'i'; bool is_signed = type_ == 'd' || type_ == 'i';
typedef typename std::conditional< typedef typename std::conditional<std::is_same<T, void>::value, U, T>::type
std::is_same<T, void>::value, U, T>::type TargetType; TargetType;
if (const_check(sizeof(TargetType) <= sizeof(int))) { if (const_check(sizeof(TargetType) <= sizeof(int))) {
// Extra casts are used to silence warnings. // Extra casts are used to silence warnings.
if (is_signed) { if (is_signed) {
@ -137,8 +133,7 @@ void convert_arg(basic_format_arg<Context> &arg, Char type) {
} }
// Converts an integer argument to char for printf. // Converts an integer argument to char for printf.
template <typename Context> template <typename Context> class char_converter : public function<void> {
class char_converter: public function<void> {
private: private:
basic_format_arg<Context>& arg_; basic_format_arg<Context>& arg_;
@ -146,8 +141,8 @@ class char_converter: public function<void> {
explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {} explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {}
template <typename T> template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type typename std::enable_if<std::is_integral<T>::value>::type operator()(
operator()(T value) { T value) {
typedef typename Context::char_type Char; typedef typename Context::char_type Char;
arg_ = internal::make_arg<Context>(static_cast<Char>(value)); arg_ = internal::make_arg<Context>(static_cast<Char>(value));
} }
@ -180,8 +175,7 @@ class printf_width_handler: public function<unsigned> {
width = 0 - width; width = 0 - width;
} }
unsigned int_max = std::numeric_limits<int>::max(); unsigned int_max = std::numeric_limits<int>::max();
if (width > int_max) if (width > int_max) FMT_THROW(format_error("number is too big"));
FMT_THROW(format_error("number is too big"));
return static_cast<unsigned>(width); return static_cast<unsigned>(width);
} }
@ -202,13 +196,11 @@ void printf(basic_buffer<Char> &buf, basic_string_view<Char> format,
using internal::printf; // For printing into memory_buffer. using internal::printf; // For printing into memory_buffer.
template <typename Range> template <typename Range> class printf_arg_formatter;
class printf_arg_formatter;
template < template <typename OutputIt, typename Char,
typename OutputIt, typename Char, typename ArgFormatter = printf_arg_formatter<
typename ArgFormatter = back_insert_range<internal::basic_buffer<Char>>>>
printf_arg_formatter<back_insert_range<internal::basic_buffer<Char>>>>
class basic_printf_context; class basic_printf_context;
/** /**
@ -217,8 +209,8 @@ class basic_printf_context;
\endrst \endrst
*/ */
template <typename Range> template <typename Range>
class printf_arg_formatter: class printf_arg_formatter
public internal::function< : public internal::function<
typename internal::arg_formatter_base<Range>::iterator>, typename internal::arg_formatter_base<Range>::iterator>,
public internal::arg_formatter_base<Range> { public internal::arg_formatter_base<Range> {
private: private:
@ -251,8 +243,8 @@ class printf_arg_formatter:
*/ */
printf_arg_formatter(internal::basic_buffer<char_type>& buffer, printf_arg_formatter(internal::basic_buffer<char_type>& buffer,
format_specs& spec, context_type& ctx) format_specs& spec, context_type& ctx)
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec, : base(back_insert_range<internal::basic_buffer<char_type>>(buffer),
ctx.locale()), &spec, ctx.locale()),
context_(ctx) {} context_(ctx) {}
template <typename T> template <typename T>
@ -262,8 +254,7 @@ class printf_arg_formatter:
// use std::is_same instead. // use std::is_same instead.
if (std::is_same<T, bool>::value) { if (std::is_same<T, bool>::value) {
format_specs& fmt_spec = *this->spec(); format_specs& fmt_spec = *this->spec();
if (fmt_spec.type != 's') if (fmt_spec.type != 's') return base::operator()(value ? 1 : 0);
return base::operator()(value ? 1 : 0);
fmt_spec.type = 0; fmt_spec.type = 0;
this->write(value != 0); this->write(value != 0);
} else if (std::is_same<T, char_type>::value) { } else if (std::is_same<T, char_type>::value) {
@ -311,14 +302,11 @@ class printf_arg_formatter:
return base::operator()(value); return base::operator()(value);
} }
iterator operator()(monostate value) { iterator operator()(monostate value) { return base::operator()(value); }
return base::operator()(value);
}
/** Formats a pointer. */ /** Formats a pointer. */
iterator operator()(const void* value) { iterator operator()(const void* value) {
if (value) if (value) return base::operator()(value);
return base::operator()(value);
this->spec()->type = 0; this->spec()->type = 0;
write_null_pointer(char_type()); write_null_pointer(char_type());
return this->out(); return this->out();
@ -331,10 +319,11 @@ class printf_arg_formatter:
} }
}; };
template <typename T> template <typename T> struct printf_formatter {
struct printf_formatter {
template <typename ParseContext> template <typename ParseContext>
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); } auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext> template <typename FormatContext>
auto format(const T& value, FormatContext& ctx) -> decltype(ctx.out()) { auto format(const T& value, FormatContext& ctx) -> decltype(ctx.out()) {
@ -354,8 +343,9 @@ class basic_printf_context :
/** The character type for the output. */ /** The character type for the output. */
typedef Char char_type; typedef Char char_type;
template <typename T> template <typename T> struct formatter_type {
struct formatter_type { typedef printf_formatter<T> type; }; typedef printf_formatter<T> type;
};
private: private:
typedef internal::context_base<OutputIt, basic_printf_context, Char> base; typedef internal::context_base<OutputIt, basic_printf_context, Char> base;
@ -383,17 +373,18 @@ class basic_printf_context :
basic_format_args<basic_printf_context> args) basic_format_args<basic_printf_context> args)
: base(out, format_str, args) {} : base(out, format_str, args) {}
using base::parse_context;
using base::out;
using base::advance_to; using base::advance_to;
using base::out;
using base::parse_context;
/** Formats stored arguments and writes the output to the range. */ /** Formats stored arguments and writes the output to the range. */
void format(); void format();
}; };
template <typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char, typename AF>
void basic_printf_context<OutputIt, Char, AF>::parse_flags( void basic_printf_context<OutputIt, Char, AF>::parse_flags(format_specs& spec,
format_specs &spec, const Char *&it, const Char *end) { const Char*& it,
const Char* end) {
for (; it != end; ++it) { for (; it != end; ++it) {
switch (*it) { switch (*it) {
case '-': case '-':
@ -439,8 +430,7 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
++it; ++it;
arg_index = value; arg_index = value;
} else { } else {
if (c == '0') if (c == '0') spec.fill_ = '0';
spec.fill_ = '0';
if (value != 0) { if (value != 0) {
// Nonzero value means that we parsed width and don't need to // Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now. // parse it or flags again, so return now.
@ -505,7 +495,8 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
format_arg arg = get_arg(arg_index); format_arg arg = get_arg(arg_index);
if (spec.has(HASH_FLAG) && visit_format_arg(internal::is_zero_int(), arg)) if (spec.has(HASH_FLAG) && visit_format_arg(internal::is_zero_int(), arg))
spec.flags = static_cast<uint_least8_t>(spec.flags & (~internal::to_unsigned<int>(HASH_FLAG))); spec.flags = static_cast<uint_least8_t>(
spec.flags & (~internal::to_unsigned<int>(HASH_FLAG)));
if (spec.fill_ == '0') { if (spec.fill_ == '0') {
if (arg.is_arithmetic()) if (arg.is_arithmetic())
spec.align_ = ALIGN_NUMERIC; spec.align_ = ALIGN_NUMERIC;
@ -555,19 +546,19 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
} }
// Parse type. // Parse type.
if (it == end) if (it == end) FMT_THROW(format_error("invalid format string"));
FMT_THROW(format_error("invalid format string"));
spec.type = static_cast<char>(*it++); spec.type = static_cast<char>(*it++);
if (arg.is_integral()) { if (arg.is_integral()) {
// Normalize type. // Normalize type.
switch (spec.type) { switch (spec.type) {
case 'i': case 'u': case 'i':
case 'u':
spec.type = 'd'; spec.type = 'd';
break; break;
case 'c': case 'c':
// TODO: handle wchar_t better? // TODO: handle wchar_t better?
visit_format_arg( visit_format_arg(internal::char_converter<basic_printf_context>(arg),
internal::char_converter<basic_printf_context>(arg), arg); arg);
break; break;
} }
} }
@ -580,10 +571,10 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
buffer.append(start, it); buffer.append(start, it);
} }
template <typename Buffer> template <typename Buffer> struct basic_printf_context_t {
struct basic_printf_context_t { typedef basic_printf_context<std::back_insert_iterator<Buffer>,
typedef basic_printf_context< typename Buffer::value_type>
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type; type;
}; };
typedef basic_printf_context_t<internal::buffer>::type printf_context; typedef basic_printf_context_t<internal::buffer>::type printf_context;
@ -599,8 +590,10 @@ typedef basic_format_args<wprintf_context> wprintf_args;
\endrst \endrst
*/ */
template <typename... Args> template <typename... Args>
inline format_arg_store<printf_context, Args...> inline format_arg_store<printf_context, Args...> make_printf_args(
make_printf_args(const Args &... args) { return {args...}; } const Args&... args) {
return {args...};
}
/** /**
\rst \rst
@ -609,14 +602,17 @@ inline format_arg_store<printf_context, Args...>
\endrst \endrst
*/ */
template <typename... Args> template <typename... Args>
inline format_arg_store<wprintf_context, Args...> inline format_arg_store<wprintf_context, Args...> make_wprintf_args(
make_wprintf_args(const Args &... args) { return {args...}; } const Args&... args) {
return {args...};
}
template <typename S, typename Char = FMT_CHAR(S)> template <typename S, typename Char = FMT_CHAR(S)>
inline std::basic_string<Char> inline std::basic_string<Char> vsprintf(
vsprintf(const S &format, const S& format,
basic_format_args<typename basic_printf_context_t< basic_format_args<
internal::basic_buffer<Char>>::type> args) { typename basic_printf_context_t<internal::basic_buffer<Char>>::type>
args) {
basic_memory_buffer<Char> buffer; basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args); printf(buffer, to_string_view(format), args);
return to_string(buffer); return to_string(buffer);
@ -632,26 +628,28 @@ vsprintf(const S &format,
\endrst \endrst
*/ */
template <typename S, typename... Args> template <typename S, typename... Args>
inline FMT_ENABLE_IF_T( inline FMT_ENABLE_IF_T(internal::is_string<S>::value,
internal::is_string<S>::value, std::basic_string<FMT_CHAR(S)>) std::basic_string<FMT_CHAR(S)>)
sprintf(const S& format, const Args&... args) { sprintf(const S& format, const Args&... args) {
internal::check_format_string<Args...>(format); internal::check_format_string<Args...>(format);
typedef internal::basic_buffer<FMT_CHAR(S)> buffer; typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
typedef typename basic_printf_context_t<buffer>::type context; typedef typename basic_printf_context_t<buffer>::type context;
format_arg_store<context, Args...> as{args...}; format_arg_store<context, Args...> as{args...};
return vsprintf(to_string_view(format), return vsprintf(to_string_view(format), basic_format_args<context>(as));
basic_format_args<context>(as));
} }
template <typename S, typename Char = FMT_CHAR(S)> template <typename S, typename Char = FMT_CHAR(S)>
inline int vfprintf(std::FILE *f, const S &format, inline int vfprintf(
basic_format_args<typename basic_printf_context_t< std::FILE* f, const S& format,
internal::basic_buffer<Char>>::type> args) { basic_format_args<
typename basic_printf_context_t<internal::basic_buffer<Char>>::type>
args) {
basic_memory_buffer<Char> buffer; basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args); printf(buffer, to_string_view(format), args);
std::size_t size = buffer.size(); std::size_t size = buffer.size();
return std::fwrite( return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size); ? -1
: static_cast<int>(size);
} }
/** /**
@ -670,14 +668,15 @@ inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
typedef internal::basic_buffer<FMT_CHAR(S)> buffer; typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
typedef typename basic_printf_context_t<buffer>::type context; typedef typename basic_printf_context_t<buffer>::type context;
format_arg_store<context, Args...> as{args...}; format_arg_store<context, Args...> as{args...};
return vfprintf(f, to_string_view(format), return vfprintf(f, to_string_view(format), basic_format_args<context>(as));
basic_format_args<context>(as));
} }
template <typename S, typename Char = FMT_CHAR(S)> template <typename S, typename Char = FMT_CHAR(S)>
inline int vprintf(const S &format, inline int vprintf(
basic_format_args<typename basic_printf_context_t< const S& format,
internal::basic_buffer<Char>>::type> args) { basic_format_args<
typename basic_printf_context_t<internal::basic_buffer<Char>>::type>
args) {
return vfprintf(stdout, to_string_view(format), args); return vfprintf(stdout, to_string_view(format), args);
} }
@ -697,15 +696,15 @@ inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
typedef internal::basic_buffer<FMT_CHAR(S)> buffer; typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
typedef typename basic_printf_context_t<buffer>::type context; typedef typename basic_printf_context_t<buffer>::type context;
format_arg_store<context, Args...> as{args...}; format_arg_store<context, Args...> as{args...};
return vprintf(to_string_view(format_str), return vprintf(to_string_view(format_str), basic_format_args<context>(as));
basic_format_args<context>(as));
} }
template <typename S, typename Char = FMT_CHAR(S)> template <typename S, typename Char = FMT_CHAR(S)>
inline int vfprintf(std::basic_ostream<Char> &os, inline int vfprintf(
const S &format, std::basic_ostream<Char>& os, const S& format,
basic_format_args<typename basic_printf_context_t< basic_format_args<
internal::basic_buffer<Char>>::type> args) { typename basic_printf_context_t<internal::basic_buffer<Char>>::type>
args) {
basic_memory_buffer<Char> buffer; basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args); printf(buffer, to_string_view(format), args);
internal::write(os, buffer); internal::write(os, buffer);
@ -723,8 +722,8 @@ inline int vfprintf(std::basic_ostream<Char> &os,
*/ */
template <typename S, typename... Args> template <typename S, typename... Args>
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int) inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
fprintf(std::basic_ostream<FMT_CHAR(S)> &os, fprintf(std::basic_ostream<FMT_CHAR(S)>& os, const S& format_str,
const S &format_str, const Args & ... args) { const Args&... args) {
internal::check_format_string<Args...>(format_str); internal::check_format_string<Args...>(format_str);
typedef internal::basic_buffer<FMT_CHAR(S)> buffer; typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
typedef typename basic_printf_context_t<buffer>::type context; typedef typename basic_printf_context_t<buffer>::type context;

View File

@ -12,8 +12,8 @@
#ifndef FMT_RANGES_H_ #ifndef FMT_RANGES_H_
#define FMT_RANGES_H_ #define FMT_RANGES_H_
#include "format.h"
#include <type_traits> #include <type_traits>
#include "format.h"
// output only up to N items from the range. // output only up to N items from the range.
#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT #ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
@ -22,8 +22,7 @@
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
template <typename Char> template <typename Char> struct formatting_base {
struct formatting_base {
template <typename ParseContext> template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin(); return ctx.begin();
@ -33,7 +32,8 @@ struct formatting_base {
template <typename Char, typename Enable = void> template <typename Char, typename Enable = void>
struct formatting_range : formatting_base<Char> { struct formatting_range : formatting_base<Char> {
static FMT_CONSTEXPR_DECL const std::size_t range_length_limit = static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the
// range.
Char prefix; Char prefix;
Char delimiter; Char delimiter;
Char postfix; Char postfix;
@ -68,19 +68,16 @@ void copy(const char *str, OutputIterator out) {
} }
} }
template <typename OutputIterator> template <typename OutputIterator> void copy(char ch, OutputIterator out) {
void copy(char ch, OutputIterator out) {
*out++ = ch; *out++ = ch;
} }
/// Return true value if T has std::string interface, like std::string_view. /// Return true value if T has std::string interface, like std::string_view.
template <typename T> template <typename T> class is_like_std_string {
class is_like_std_string {
template <typename U> template <typename U>
static auto check(U *p) -> static auto check(U* p)
decltype(p->find('a'), p->length(), p->data(), int()); -> decltype(p->find('a'), p->length(), p->data(), int());
template <typename> template <typename> static void check(...);
static void check(...);
public: public:
static FMT_CONSTEXPR_DECL const bool value = static FMT_CONSTEXPR_DECL const bool value =
@ -90,15 +87,14 @@ class is_like_std_string {
template <typename Char> template <typename Char>
struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {}; struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {};
template <typename... Ts> template <typename... Ts> struct conditional_helper {};
struct conditional_helper {};
template <typename T, typename _ = void> template <typename T, typename _ = void> struct is_range_ : std::false_type {};
struct is_range_ : std::false_type {};
#if !FMT_MSC_VER || FMT_MSC_VER > 1800 #if !FMT_MSC_VER || FMT_MSC_VER > 1800
template <typename T> template <typename T>
struct is_range_<T, typename std::conditional< struct is_range_<
T, typename std::conditional<
false, false,
conditional_helper<decltype(internal::declval<T>().begin()), conditional_helper<decltype(internal::declval<T>().begin()),
decltype(internal::declval<T>().end())>, decltype(internal::declval<T>().end())>,
@ -106,14 +102,13 @@ struct is_range_<T, typename std::conditional<
#endif #endif
/// tuple_size and tuple_element check. /// tuple_size and tuple_element check.
template <typename T> template <typename T> class is_tuple_like_ {
class is_tuple_like_ {
template <typename U> template <typename U>
static auto check(U *p) -> static auto check(U* p)
decltype(std::tuple_size<U>::value, -> decltype(std::tuple_size<U>::value,
internal::declval<typename std::tuple_element<0, U>::type>(), int()); internal::declval<typename std::tuple_element<0, U>::type>(),
template <typename> int());
static void check(...); template <typename> static void check(...);
public: public:
static FMT_CONSTEXPR_DECL const bool value = static FMT_CONSTEXPR_DECL const bool value =
@ -124,18 +119,14 @@ class is_tuple_like_ {
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900 #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
template <typename T, T... N> template <typename T, T... N>
using integer_sequence = std::integer_sequence<T, N...>; using integer_sequence = std::integer_sequence<T, N...>;
template <std::size_t... N> template <std::size_t... N> using index_sequence = std::index_sequence<N...>;
using index_sequence = std::index_sequence<N...>;
template <std::size_t N> template <std::size_t N>
using make_index_sequence = std::make_index_sequence<N>; using make_index_sequence = std::make_index_sequence<N>;
#else #else
template <typename T, T... N> template <typename T, T... N> struct integer_sequence {
struct integer_sequence {
typedef T value_type; typedef T value_type;
static FMT_CONSTEXPR std::size_t size() { static FMT_CONSTEXPR std::size_t size() { return sizeof...(N); }
return sizeof...(N);
}
}; };
template <std::size_t... N> template <std::size_t... N>
@ -159,26 +150,31 @@ void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT {
} }
template <class T> template <class T>
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(
get_indexes(T const &) { return {}; } T const&) {
return {};
}
template <class Tuple, class F> template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
void for_each(Tuple &&tup, F &&f) {
const auto indexes = get_indexes(tup); const auto indexes = get_indexes(tup);
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f)); for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
} }
template <typename Arg> template <typename Arg>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&, FMT_CONSTEXPR const char* format_str_quoted(
bool add_space, const Arg&,
typename std::enable_if< typename std::enable_if<
!is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) { !is_like_std_string<typename std::decay<Arg>::type>::value>::type* =
nullptr) {
return add_space ? " {}" : "{}"; return add_space ? " {}" : "{}";
} }
template <typename Arg> template <typename Arg>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&, FMT_CONSTEXPR const char* format_str_quoted(
bool add_space, const Arg&,
typename std::enable_if< typename std::enable_if<
is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) { is_like_std_string<typename std::decay<Arg>::type>::value>::type* =
nullptr) {
return add_space ? " \"{}\"" : "\"{}\""; return add_space ? " \"{}\"" : "\"{}\"";
} }
@ -198,21 +194,19 @@ FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
} // namespace internal } // namespace internal
template <typename T> template <typename T> struct is_tuple_like {
struct is_tuple_like {
static FMT_CONSTEXPR_DECL const bool value = static FMT_CONSTEXPR_DECL const bool value =
internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value; internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
}; };
template <typename TupleT, typename Char> template <typename TupleT, typename Char>
struct formatter<TupleT, Char, struct formatter<
TupleT, Char,
typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> { typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> {
private: private:
// C++11 generic lambda for format() // C++11 generic lambda for format()
template <typename FormatContext> template <typename FormatContext> struct format_each {
struct format_each { template <typename T> void operator()(const T& v) {
template <typename T>
void operator()(const T& v) {
if (i > 0) { if (i > 0) {
if (formatting.add_prepostfix_space) { if (formatting.add_prepostfix_space) {
*out++ = ' '; *out++ = ' ';
@ -228,7 +222,8 @@ private:
formatting_tuple<Char>& formatting; formatting_tuple<Char>& formatting;
std::size_t& i; std::size_t& i;
typename std::add_lvalue_reference<decltype(std::declval<FormatContext>().out())>::type out; typename std::add_lvalue_reference<decltype(
std::declval<FormatContext>().out())>::type out;
}; };
public: public:
@ -255,8 +250,7 @@ public:
} }
}; };
template <typename T> template <typename T> struct is_range {
struct is_range {
static FMT_CONSTEXPR_DECL const bool value = static FMT_CONSTEXPR_DECL const bool value =
internal::is_range_<T>::value && !internal::is_like_std_string<T>::value; internal::is_range_<T>::value && !internal::is_like_std_string<T>::value;
}; };
@ -264,7 +258,6 @@ struct is_range {
template <typename RangeT, typename Char> template <typename RangeT, typename Char>
struct formatter<RangeT, Char, struct formatter<RangeT, Char,
typename std::enable_if<fmt::is_range<RangeT>::value>::type> { typename std::enable_if<fmt::is_range<RangeT>::value>::type> {
formatting_range<Char> formatting; formatting_range<Char> formatting;
template <typename ParseContext> template <typename ParseContext>
@ -273,8 +266,8 @@ struct formatter<RangeT, Char,
} }
template <typename FormatContext> template <typename FormatContext>
typename FormatContext::iterator format( typename FormatContext::iterator format(const RangeT& values,
const RangeT &values, FormatContext &ctx) { FormatContext& ctx) {
auto out = ctx.out(); auto out = ctx.out();
internal::copy(formatting.prefix, out); internal::copy(formatting.prefix, out);
std::size_t i = 0; std::size_t i = 0;
@ -305,4 +298,3 @@ struct formatter<RangeT, Char,
FMT_END_NAMESPACE FMT_END_NAMESPACE
#endif // FMT_RANGES_H_ #endif // FMT_RANGES_H_

View File

@ -8,9 +8,9 @@
#ifndef FMT_TIME_H_ #ifndef FMT_TIME_H_
#define FMT_TIME_H_ #define FMT_TIME_H_
#include "format.h"
#include <ctime> #include <ctime>
#include <locale> #include <locale>
#include "format.h"
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
@ -58,8 +58,7 @@ inline std::tm localtime(std::time_t time) {
}; };
dispatcher lt(time); dispatcher lt(time);
// Too big time values may be unsupported. // Too big time values may be unsupported.
if (!lt.run()) if (!lt.run()) FMT_THROW(format_error("time_t value out of range"));
FMT_THROW(format_error("time_t value out of range"));
return lt.tm_; return lt.tm_;
} }
@ -95,8 +94,7 @@ inline std::tm gmtime(std::time_t time) {
}; };
dispatcher gt(time); dispatcher gt(time);
// Too big time values may be unsupported. // Too big time values may be unsupported.
if (!gt.run()) if (!gt.run()) FMT_THROW(format_error("time_t value out of range"));
FMT_THROW(format_error("time_t value out of range"));
return gt.tm_; return gt.tm_;
} }
@ -110,18 +108,15 @@ inline std::size_t strftime(wchar_t *str, std::size_t count,
const wchar_t* format, const std::tm* time) { const wchar_t* format, const std::tm* time) {
return std::wcsftime(str, count, format, time); return std::wcsftime(str, count, format, time);
} }
} } // namespace internal
template <typename Char> template <typename Char> struct formatter<std::tm, Char> {
struct formatter<std::tm, Char> {
template <typename ParseContext> template <typename ParseContext>
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
auto it = ctx.begin(); auto it = ctx.begin();
if (it != ctx.end() && *it == ':') if (it != ctx.end() && *it == ':') ++it;
++it;
auto end = it; auto end = it;
while (end != ctx.end() && *end != '}') while (end != ctx.end() && *end != '}') ++end;
++end;
tm_format.reserve(internal::to_unsigned(end - it + 1)); tm_format.reserve(internal::to_unsigned(end - it + 1));
tm_format.append(it, end); tm_format.append(it, end);
tm_format.push_back('\0'); tm_format.push_back('\0');

View File

@ -16,16 +16,21 @@ template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
template FMT_API char internal::thousands_sep_impl(locale_ref); template FMT_API char internal::thousands_sep_impl(locale_ref);
template FMT_API void internal::basic_buffer<char>::append(const char *, const char *); template FMT_API void internal::basic_buffer<char>::append(const char*,
const char*);
template FMT_API void internal::arg_map<format_context>::init( template FMT_API void internal::arg_map<format_context>::init(
const basic_format_args<format_context>& args); const basic_format_args<format_context>& args);
template FMT_API int internal::char_traits<char>::format_float( template FMT_API int internal::char_traits<char>::format_float(char*,
char *, std::size_t, const char *, int, double); std::size_t,
const char*, int,
double);
template FMT_API int internal::char_traits<char>::format_float( template FMT_API int internal::char_traits<char>::format_float(char*,
char *, std::size_t, const char *, int, long double); std::size_t,
const char*, int,
long double);
template FMT_API std::string internal::vformat<char>( template FMT_API std::string internal::vformat<char>(
string_view, basic_format_args<format_context>); string_view, basic_format_args<format_context>);
@ -33,17 +38,17 @@ template FMT_API std::string internal::vformat<char>(
template FMT_API format_context::iterator internal::vformat_to( template FMT_API format_context::iterator internal::vformat_to(
internal::buffer&, string_view, basic_format_args<format_context>); internal::buffer&, string_view, basic_format_args<format_context>);
template FMT_API void internal::sprintf_format( template FMT_API void internal::sprintf_format(double, internal::buffer&,
double, internal::buffer &, core_format_specs); core_format_specs);
template FMT_API void internal::sprintf_format( template FMT_API void internal::sprintf_format(long double, internal::buffer&,
long double, internal::buffer &, core_format_specs); core_format_specs);
// Explicit instantiations for wchar_t. // Explicit instantiations for wchar_t.
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref); template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
template FMT_API void internal::basic_buffer<wchar_t>::append( template FMT_API void internal::basic_buffer<wchar_t>::append(const wchar_t*,
const wchar_t *, const wchar_t *); const wchar_t*);
template FMT_API void internal::arg_map<wformat_context>::init( template FMT_API void internal::arg_map<wformat_context>::init(
const basic_format_args<wformat_context>&); const basic_format_args<wformat_context>&);

View File

@ -13,8 +13,8 @@
#include "fmt/posix.h" #include "fmt/posix.h"
#include <limits.h> #include <limits.h>
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h>
#ifndef _WIN32 #ifndef _WIN32
# include <unistd.h> # include <unistd.h>
@ -22,8 +22,8 @@
# ifndef WIN32_LEAN_AND_MEAN # ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN
# endif # endif
# include <windows.h>
# include <io.h> # include <io.h>
# include <windows.h>
# define O_CREAT _O_CREAT # define O_CREAT _O_CREAT
# define O_TRUNC _O_TRUNC # define O_TRUNC _O_TRUNC
@ -62,7 +62,7 @@ typedef ssize_t RWResult;
inline std::size_t convert_rwcount(std::size_t count) { return count; } inline std::size_t convert_rwcount(std::size_t count) { return count; }
#endif #endif
} } // namespace
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
@ -72,19 +72,17 @@ buffered_file::~buffered_file() FMT_NOEXCEPT {
} }
buffered_file::buffered_file(cstring_view filename, cstring_view mode) { buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
FMT_RETRY_VAL(file_, FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), FMT_NULL); FMT_NULL);
if (!file_) if (!file_)
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str())); FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
} }
void buffered_file::close() { void buffered_file::close() {
if (!file_) if (!file_) return;
return;
int result = FMT_SYSTEM(fclose(file_)); int result = FMT_SYSTEM(fclose(file_));
file_ = FMT_NULL; file_ = FMT_NULL;
if (result != 0) if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
FMT_THROW(system_error(errno, "cannot close file"));
} }
// A macro used to prevent expansion of fileno on broken versions of MinGW. // A macro used to prevent expansion of fileno on broken versions of MinGW.
@ -92,8 +90,7 @@ void buffered_file::close() {
int buffered_file::fileno() const { int buffered_file::fileno() const {
int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_)); int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
if (fd == -1) if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor"));
FMT_THROW(system_error(errno, "cannot get file descriptor"));
return fd; return fd;
} }
@ -117,14 +114,12 @@ file::~file() FMT_NOEXCEPT {
} }
void file::close() { void file::close() {
if (fd_ == -1) if (fd_ == -1) return;
return;
// Don't retry close in case of EINTR! // Don't retry close in case of EINTR!
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
int result = FMT_POSIX_CALL(close(fd_)); int result = FMT_POSIX_CALL(close(fd_));
fd_ = -1; fd_ = -1;
if (result != 0) if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
FMT_THROW(system_error(errno, "cannot close file"));
} }
long long file::size() const { long long file::size() const {
@ -156,16 +151,14 @@ long long file::size() const {
std::size_t file::read(void* buffer, std::size_t count) { std::size_t file::read(void* buffer, std::size_t count) {
RWResult result = 0; RWResult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
if (result < 0) if (result < 0) FMT_THROW(system_error(errno, "cannot read from file"));
FMT_THROW(system_error(errno, "cannot read from file"));
return internal::to_unsigned(result); return internal::to_unsigned(result);
} }
std::size_t file::write(const void* buffer, std::size_t count) { std::size_t file::write(const void* buffer, std::size_t count) {
RWResult result = 0; RWResult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
if (result < 0) if (result < 0) FMT_THROW(system_error(errno, "cannot write to file"));
FMT_THROW(system_error(errno, "cannot write to file"));
return internal::to_unsigned(result); return internal::to_unsigned(result);
} }
@ -182,16 +175,15 @@ void file::dup2(int fd) {
int result = 0; int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) { if (result == -1) {
FMT_THROW(system_error(errno, FMT_THROW(system_error(errno, "cannot duplicate file descriptor {} to {}",
"cannot duplicate file descriptor {} to {}", fd_, fd)); fd_, fd));
} }
} }
void file::dup2(int fd, error_code& ec) FMT_NOEXCEPT { void file::dup2(int fd, error_code& ec) FMT_NOEXCEPT {
int result = 0; int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) if (result == -1) ec = error_code(errno);
ec = error_code(errno);
} }
void file::pipe(file& read_end, file& write_end) { void file::pipe(file& read_end, file& write_end) {
@ -209,8 +201,7 @@ void file::pipe(file &read_end, file &write_end) {
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
int result = FMT_POSIX_CALL(pipe(fds)); int result = FMT_POSIX_CALL(pipe(fds));
#endif #endif
if (result != 0) if (result != 0) FMT_THROW(system_error(errno, "cannot create pipe"));
FMT_THROW(system_error(errno, "cannot create pipe"));
// The following assignments don't throw because read_fd and write_fd // The following assignments don't throw because read_fd and write_fd
// are closed. // are closed.
read_end = file(fds[0]); read_end = file(fds[0]);
@ -221,8 +212,8 @@ buffered_file file::fdopen(const char *mode) {
// Don't retry as fdopen doesn't return EINTR. // Don't retry as fdopen doesn't return EINTR.
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode)); FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
if (!f) if (!f)
FMT_THROW(system_error(errno, FMT_THROW(
"cannot associate stream with file descriptor")); system_error(errno, "cannot associate stream with file descriptor"));
buffered_file bf(f); buffered_file bf(f);
fd_ = -1; fd_ = -1;
return bf; return bf;
@ -235,10 +226,8 @@ long getpagesize() {
return si.dwPageSize; return si.dwPageSize;
#else #else
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
if (size < 0) if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size"));
FMT_THROW(system_error(errno, "cannot get memory page size"));
return size; return size;
#endif #endif
} }
FMT_END_NAMESPACE FMT_END_NAMESPACE

View File

@ -17,6 +17,6 @@
#endif #endif
TEST(AssertTest, Fail) { TEST(AssertTest, Fail) {
EXPECT_DEBUG_DEATH_IF_SUPPORTED( EXPECT_DEBUG_DEATH_IF_SUPPORTED(FMT_ASSERT(false, "don't panic!"),
FMT_ASSERT(false, "don't panic!"), "don't panic!"); "don't panic!");
} }

View File

@ -43,7 +43,8 @@ std::string format_tm(const std::tm &time, const char *spec,
return os.str(); return os.str();
} }
#define EXPECT_TIME(spec, time, duration) { \ #define EXPECT_TIME(spec, time, duration) \
{ \
std::locale loc("ja_JP.utf8"); \ std::locale loc("ja_JP.utf8"); \
EXPECT_EQ(format_tm(time, spec, loc), \ EXPECT_EQ(format_tm(time, spec, loc), \
fmt::format(loc, "{:" spec "}", duration)); \ fmt::format(loc, "{:" spec "}", duration)); \
@ -83,12 +84,12 @@ TEST(ChronoTest, FormatDefault) {
fmt::format("{}", std::chrono::duration<int, std::exa>(42))); fmt::format("{}", std::chrono::duration<int, std::exa>(42)));
EXPECT_EQ("42m", fmt::format("{}", std::chrono::minutes(42))); EXPECT_EQ("42m", fmt::format("{}", std::chrono::minutes(42)));
EXPECT_EQ("42h", fmt::format("{}", std::chrono::hours(42))); EXPECT_EQ("42h", fmt::format("{}", std::chrono::hours(42)));
EXPECT_EQ("42[15]s", EXPECT_EQ(
fmt::format("{}", "42[15]s",
std::chrono::duration<int, std::ratio<15, 1>>(42))); fmt::format("{}", std::chrono::duration<int, std::ratio<15, 1>>(42)));
EXPECT_EQ("42[15/4]s", EXPECT_EQ(
fmt::format("{}", "42[15/4]s",
std::chrono::duration<int, std::ratio<15, 4>>(42))); fmt::format("{}", std::chrono::duration<int, std::ratio<15, 4>>(42)));
} }
TEST(ChronoTest, Align) { TEST(ChronoTest, Align) {
@ -105,7 +106,6 @@ TEST(ChronoTest, Align) {
fmt::format("{:~^12%H:%M:%S}", std::chrono::seconds(12345))); fmt::format("{:~^12%H:%M:%S}", std::chrono::seconds(12345)));
EXPECT_EQ("03:25:45 ", EXPECT_EQ("03:25:45 ",
fmt::format("{:{}%H:%M:%S}", std::chrono::seconds(12345), 12)); fmt::format("{:{}%H:%M:%S}", std::chrono::seconds(12345), 12));
} }
TEST(ChronoTest, FormatSpecs) { TEST(ChronoTest, FormatSpecs) {
@ -168,7 +168,8 @@ TEST(ChronoTest, Locale) {
try { try {
loc = std::locale(loc_name); loc = std::locale(loc_name);
has_locale = true; has_locale = true;
} catch (const std::runtime_error &) {} } catch (const std::runtime_error&) {
}
if (!has_locale) { if (!has_locale) {
fmt::print("{} locale is missing.\n", loc_name); fmt::print("{} locale is missing.\n", loc_name);
return; return;

View File

@ -11,9 +11,9 @@
#include <functional> #include <functional>
#include <iterator> #include <iterator>
#include <limits> #include <limits>
#include <memory>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <memory>
#include "test-assert.h" #include "test-assert.h"
@ -30,9 +30,9 @@
#undef max #undef max
using fmt::basic_format_arg; using fmt::basic_format_arg;
using fmt::string_view;
using fmt::internal::basic_buffer; using fmt::internal::basic_buffer;
using fmt::internal::value; using fmt::internal::value;
using fmt::string_view;
using testing::_; using testing::_;
using testing::StrictMock; using testing::StrictMock;
@ -48,8 +48,7 @@ basic_format_arg<Context> make_arg(const T &value) {
} // namespace } // namespace
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
template <typename Char> template <typename Char> struct formatter<test_struct, Char> {
struct formatter<test_struct, Char> {
template <typename ParseContext> template <typename ParseContext>
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin(); return ctx.begin();
@ -84,13 +83,11 @@ TEST(BufferTest, Nonmoveable) {
#endif #endif
// A test buffer with a dummy grow method. // A test buffer with a dummy grow method.
template <typename T> template <typename T> struct test_buffer : basic_buffer<T> {
struct test_buffer : basic_buffer<T> {
void grow(std::size_t capacity) { this->set(FMT_NULL, capacity); } void grow(std::size_t capacity) { this->set(FMT_NULL, capacity); }
}; };
template <typename T> template <typename T> struct mock_buffer : basic_buffer<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) { void grow(std::size_t capacity) {
@ -211,8 +208,7 @@ TEST(ArgTest, FormatArgs) {
struct custom_context { struct custom_context {
typedef char char_type; typedef char char_type;
template <typename T> template <typename T> struct formatter_type {
struct formatter_type {
struct type { struct type {
template <typename ParseContext> template <typename ParseContext>
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
@ -249,17 +245,15 @@ template <typename Char>
bool operator==(custom_value<Char> lhs, custom_value<Char> rhs) { bool operator==(custom_value<Char> lhs, custom_value<Char> rhs) {
return lhs.value == rhs.value; return lhs.value == rhs.value;
} }
} } // namespace internal
FMT_END_NAMESPACE FMT_END_NAMESPACE
// Use a unique result type to make sure that there are no undesirable // Use a unique result type to make sure that there are no undesirable
// conversions. // conversions.
struct test_result {}; struct test_result {};
template <typename T> template <typename T> struct mock_visitor {
struct mock_visitor { template <typename U> struct result { typedef test_result type; };
template <typename U>
struct result { typedef test_result type; };
mock_visitor() { mock_visitor() {
ON_CALL(*this, visit(_)).WillByDefault(testing::Return(test_result())); ON_CALL(*this, visit(_)).WillByDefault(testing::Return(test_result()));
@ -270,19 +264,16 @@ struct mock_visitor {
test_result operator()(T value) { return visit(value); } test_result operator()(T value) { return visit(value); }
template <typename U> template <typename U> test_result operator()(U) {
test_result operator()(U) {
unexpected(); unexpected();
return test_result(); return test_result();
} }
}; };
template <typename T> template <typename T> struct visit_type { typedef T Type; };
struct visit_type { typedef T Type; };
#define VISIT_TYPE(Type_, visit_type_) \ #define VISIT_TYPE(Type_, visit_type_) \
template <> \ template <> struct visit_type<Type_> { typedef visit_type_ Type; }
struct visit_type<Type_> { typedef visit_type_ Type; }
VISIT_TYPE(signed char, int); VISIT_TYPE(signed char, int);
VISIT_TYPE(unsigned char, unsigned); VISIT_TYPE(unsigned char, unsigned);
@ -299,7 +290,8 @@ VISIT_TYPE(unsigned long, unsigned long long);
VISIT_TYPE(float, double); VISIT_TYPE(float, double);
#define CHECK_ARG_(Char, expected, value) { \ #define CHECK_ARG_(Char, expected, value) \
{ \
testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \ testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
EXPECT_CALL(visitor, visit(expected)); \ EXPECT_CALL(visitor, visit(expected)); \
typedef std::back_insert_iterator<basic_buffer<Char>> iterator; \ typedef std::back_insert_iterator<basic_buffer<Char>> iterator; \
@ -307,20 +299,21 @@ VISIT_TYPE(float, double);
make_arg<fmt::basic_format_context<iterator, Char>>(value)); \ make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
} }
#define CHECK_ARG(value, typename_) { \ #define CHECK_ARG(value, typename_) \
{ \
typedef decltype(value) value_type; \ typedef decltype(value) value_type; \
typename_ visit_type<value_type>::Type expected = value; \ typename_ visit_type<value_type>::Type expected = value; \
CHECK_ARG_(char, expected, value) \ CHECK_ARG_(char, expected, value) \
CHECK_ARG_(wchar_t, expected, value) \ CHECK_ARG_(wchar_t, expected, value) \
} }
template <typename T> template <typename T> class NumericArgTest : public testing::Test {};
class NumericArgTest : public testing::Test {};
typedef ::testing::Types< typedef ::testing::Types<bool, signed char, unsigned char, signed,
bool, signed char, unsigned char, signed, unsigned short, unsigned short, int, unsigned, long, unsigned long,
int, unsigned, long, unsigned long, long long, unsigned long long, long long, unsigned long long, float, double,
float, double, long double> Types; long double>
Types;
TYPED_TEST_CASE(NumericArgTest, Types); TYPED_TEST_CASE(NumericArgTest, Types);
template <typename T> template <typename T>
@ -416,8 +409,7 @@ TEST(StringViewTest, Length) {
} }
// Check string_view's comparison operator. // Check string_view's comparison operator.
template <template <typename> class Op> template <template <typename> class Op> void check_op() {
void check_op() {
const char* inputs[] = {"foo", "fop", "fo"}; const char* inputs[] = {"foo", "fop", "fo"};
std::size_t num_inputs = sizeof(inputs) / sizeof(*inputs); std::size_t num_inputs = sizeof(inputs) / sizeof(*inputs);
for (std::size_t i = 0; i < num_inputs; ++i) { for (std::size_t i = 0; i < num_inputs; ++i) {
@ -457,25 +449,25 @@ TEST(CoreTest, IsEnumConvertibleToInt) {
} }
namespace my_ns { namespace my_ns {
template <typename Char> template <typename Char> class my_string {
class my_string {
public: public:
my_string(const Char* s) : s_(s) {} 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(); } 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: private:
std::basic_string<Char> s_; std::basic_string<Char> s_;
}; };
template <typename Char> template <typename Char>
inline fmt::basic_string_view<Char> inline fmt::basic_string_view<Char> to_string_view(const my_string<Char>& s)
to_string_view(const my_string<Char> &s) FMT_NOEXCEPT { FMT_NOEXCEPT {
return {s.data(), s.length()}; return {s.data(), s.length()};
} }
struct non_string {}; struct non_string {};
} } // namespace my_ns
namespace FakeQt { namespace FakeQt {
class QString { class QString {
@ -490,15 +482,13 @@ class QString {
std::shared_ptr<std::wstring> s_; std::shared_ptr<std::wstring> s_;
}; };
inline fmt::basic_string_view<wchar_t> to_string_view( inline fmt::basic_string_view<wchar_t> to_string_view(const QString& s)
const QString &s) FMT_NOEXCEPT { FMT_NOEXCEPT {
return {s.utf16(), return {s.utf16(), static_cast<std::size_t>(s.size())};
static_cast<std::size_t>(s.size())};
}
} }
} // namespace FakeQt
template <typename T> template <typename T> class IsStringTest : public testing::Test {};
class IsStringTest : public testing::Test {};
typedef ::testing::Types<char, wchar_t, char16_t, char32_t> StringCharTypes; typedef ::testing::Types<char, wchar_t, char16_t, char32_t> StringCharTypes;
TYPED_TEST_CASE(IsStringTest, StringCharTypes); TYPED_TEST_CASE(IsStringTest, StringCharTypes);
@ -506,7 +496,7 @@ TYPED_TEST_CASE(IsStringTest, StringCharTypes);
namespace { namespace {
template <typename Char> template <typename Char>
struct derived_from_string_view : fmt::basic_string_view<Char> {}; struct derived_from_string_view : fmt::basic_string_view<Char> {};
} } // namespace
TYPED_TEST(IsStringTest, IsString) { TYPED_TEST(IsStringTest, IsString) {
EXPECT_TRUE((fmt::internal::is_string<TypeParam*>::value)); EXPECT_TRUE((fmt::internal::is_string<TypeParam*>::value));
@ -600,11 +590,12 @@ TEST(FormatterTest, FormatExplicitlyConvertibleToWStringView) {
} }
struct explicitly_convertible_to_string_like { struct explicitly_convertible_to_string_like {
template < template <typename String,
typename String, typename = typename std::enable_if<std::is_constructible<
typename = typename std::enable_if< String, const char*, std::size_t>::value>::type>
std::is_constructible<String, const char*, std::size_t>::value>::type> FMT_EXPLICIT operator String() const {
FMT_EXPLICIT operator String() const { return String("foo", 3u); } return String("foo", 3u);
}
}; };
TEST(FormatterTest, FormatExplicitlyConvertibleToStringLike) { TEST(FormatterTest, FormatExplicitlyConvertibleToStringLike) {

View File

@ -13,22 +13,21 @@
// A custom argument formatter that doesn't print `-` for floating-point values // A custom argument formatter that doesn't print `-` for floating-point values
// rounded to 0. // rounded to 0.
class custom_arg_formatter : class custom_arg_formatter
public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> { : public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
public: public:
typedef fmt::back_insert_range<fmt::internal::buffer> range; typedef fmt::back_insert_range<fmt::internal::buffer> range;
typedef fmt::arg_formatter<range> base; typedef fmt::arg_formatter<range> base;
custom_arg_formatter( custom_arg_formatter(fmt::format_context& ctx,
fmt::format_context &ctx, fmt::format_specs *s = FMT_NULL) fmt::format_specs* s = FMT_NULL)
: base(ctx, s) {} : base(ctx, s) {}
using base::operator(); using base::operator();
iterator operator()(double value) { iterator operator()(double value) {
// Comparing a float to 0.0 is safe. // Comparing a float to 0.0 is safe.
if (round(value * pow(10, spec()->precision)) == 0.0) if (round(value * pow(10, spec()->precision)) == 0.0) value = 0;
value = 0;
return base::operator()(value); return base::operator()(value);
} }
}; };

View File

@ -32,13 +32,11 @@
using fmt::internal::fp; using fmt::internal::fp;
template <bool is_iec559> template <bool is_iec559> void test_construct_from_double() {
void test_construct_from_double() {
fmt::print("warning: double is not IEC559, skipping FP tests\n"); fmt::print("warning: double is not IEC559, skipping FP tests\n");
} }
template <> template <> void test_construct_from_double<true>() {
void test_construct_from_double<true>() {
auto v = fp(1.23); auto v = fp(1.23);
EXPECT_EQ(v.f, 0x13ae147ae147aeu); EXPECT_EQ(v.f, 0x13ae147ae147aeu);
EXPECT_EQ(v.e, -52); EXPECT_EQ(v.e, -52);
@ -107,14 +105,10 @@ TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) {
grisu2_format(4.2f, buf, fmt::core_format_specs()); grisu2_format(4.2f, buf, fmt::core_format_specs());
} }
template <typename T> template <typename T> struct ValueExtractor : fmt::internal::function<T> {
struct ValueExtractor: fmt::internal::function<T> { T operator()(T value) { return value; }
T operator()(T value) {
return value;
}
template <typename U> template <typename U> FMT_NORETURN T operator()(U) {
FMT_NORETURN T operator()(U) {
throw std::runtime_error(fmt::format("invalid type {}", typeid(U).name())); throw std::runtime_error(fmt::format("invalid type {}", typeid(U).name()));
} }
}; };
@ -178,8 +172,8 @@ TEST(FormatTest, FormatErrorCode) {
} }
{ {
fmt::memory_buffer buffer; fmt::memory_buffer buffer;
std::string prefix( std::string prefix(fmt::inline_buffer_size - msg.size() - sep.size() + 1,
fmt::inline_buffer_size - msg.size() - sep.size() + 1, 'x'); 'x');
fmt::format_error_code(buffer, 42, prefix); fmt::format_error_code(buffer, 42, prefix);
EXPECT_EQ(msg, to_string(buffer)); EXPECT_EQ(msg, to_string(buffer));
} }
@ -188,8 +182,7 @@ TEST(FormatTest, FormatErrorCode) {
// Test maximum buffer size. // Test maximum buffer size.
msg = fmt::format("error {}", codes[i]); msg = fmt::format("error {}", codes[i]);
fmt::memory_buffer buffer; fmt::memory_buffer buffer;
std::string prefix( std::string prefix(fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
fmt::format_error_code(buffer, codes[i], prefix); fmt::format_error_code(buffer, codes[i], prefix);
EXPECT_EQ(prefix + sep + msg, to_string(buffer)); EXPECT_EQ(prefix + sep + msg, to_string(buffer));
std::size_t size = fmt::inline_buffer_size; std::size_t size = fmt::inline_buffer_size;
@ -250,17 +243,18 @@ TEST(ColorsTest, ColorsFormat) {
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m"); "\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue"), EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue"),
"\x1b[38;2;000;000;255mblue\x1b[0m"); "\x1b[38;2;000;000;255mblue\x1b[0m");
EXPECT_EQ(fmt::format(fg(fmt::color::blue) | bg(fmt::color::red), "two color"), EXPECT_EQ(
fmt::format(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"); "\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold"), EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold"), "\x1b[1mbold\x1b[0m");
"\x1b[1mbold\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::italic, "italic"), EXPECT_EQ(fmt::format(fmt::emphasis::italic, "italic"),
"\x1b[3mitalic\x1b[0m"); "\x1b[3mitalic\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::underline, "underline"), EXPECT_EQ(fmt::format(fmt::emphasis::underline, "underline"),
"\x1b[4munderline\x1b[0m"); "\x1b[4munderline\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::strikethrough, "strikethrough"), EXPECT_EQ(fmt::format(fmt::emphasis::strikethrough, "strikethrough"),
"\x1b[9mstrikethrough\x1b[0m"); "\x1b[9mstrikethrough\x1b[0m");
EXPECT_EQ(fmt::format(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"), EXPECT_EQ(
fmt::format(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"),
"\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m"); "\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold error"), EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold error"),
"\x1b[1mbold error\x1b[0m"); "\x1b[1mbold error\x1b[0m");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -7,11 +7,11 @@
#include "gtest-extra.h" #include "gtest-extra.h"
#include <gtest/gtest-spi.h>
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <stdexcept> #include <stdexcept>
#include <gtest/gtest-spi.h>
#if defined(_WIN32) && !defined(__MINGW32__) #if defined(_WIN32) && !defined(__MINGW32__)
# include <crtdbg.h> // for _CrtSetReportMode # include <crtdbg.h> // for _CrtSetReportMode
@ -52,13 +52,9 @@ int SingleEvaluationTest::b_;
void do_nothing() {} void do_nothing() {}
void throw_exception() { void throw_exception() { throw std::runtime_error("test"); }
throw std::runtime_error("test");
}
void throw_system_error() { void throw_system_error() { throw fmt::system_error(EDOM, "test"); }
throw fmt::system_error(EDOM, "test");
}
// Tests that when EXPECT_THROW_MSG fails, it evaluates its message argument // Tests that when EXPECT_THROW_MSG fails, it evaluates its message argument
// exactly once. // exactly once.
@ -71,42 +67,49 @@ TEST_F(SingleEvaluationTest, FailedEXPECT_THROW_MSG) {
// Tests that when EXPECT_SYSTEM_ERROR fails, it evaluates its message argument // Tests that when EXPECT_SYSTEM_ERROR fails, it evaluates its message argument
// exactly once. // exactly once.
TEST_F(SingleEvaluationTest, FailedEXPECT_SYSTEM_ERROR) { TEST_F(SingleEvaluationTest, FailedEXPECT_SYSTEM_ERROR) {
EXPECT_NONFATAL_FAILURE( EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, p_++),
EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, p_++), "01234"); "01234");
EXPECT_EQ(s_ + 1, p_); EXPECT_EQ(s_ + 1, p_);
} }
// Tests that when EXPECT_WRITE fails, it evaluates its message argument // Tests that when EXPECT_WRITE fails, it evaluates its message argument
// exactly once. // exactly once.
TEST_F(SingleEvaluationTest, FailedEXPECT_WRITE) { TEST_F(SingleEvaluationTest, FailedEXPECT_WRITE) {
EXPECT_NONFATAL_FAILURE( EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), p_++),
EXPECT_WRITE(stdout, std::printf("test"), p_++), "01234"); "01234");
EXPECT_EQ(s_ + 1, p_); EXPECT_EQ(s_ + 1, p_);
} }
// Tests that assertion arguments are evaluated exactly once. // Tests that assertion arguments are evaluated exactly once.
TEST_F(SingleEvaluationTest, ExceptionTests) { TEST_F(SingleEvaluationTest, ExceptionTests) {
// successful EXPECT_THROW_MSG // successful EXPECT_THROW_MSG
EXPECT_THROW_MSG({ // NOLINT EXPECT_THROW_MSG(
{ // NOLINT
a_++; a_++;
throw_exception(); throw_exception();
}, std::exception, (b_++, "test")); },
std::exception, (b_++, "test"));
EXPECT_EQ(1, a_); EXPECT_EQ(1, a_);
EXPECT_EQ(1, b_); EXPECT_EQ(1, b_);
// failed EXPECT_THROW_MSG, throws different type // failed EXPECT_THROW_MSG, throws different type
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG({ // NOLINT EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(
{ // NOLINT
a_++; a_++;
throw_exception(); throw_exception();
}, std::logic_error, (b_++, "test")), "throws a different type"); },
std::logic_error, (b_++, "test")),
"throws a different type");
EXPECT_EQ(2, a_); EXPECT_EQ(2, a_);
EXPECT_EQ(2, b_); EXPECT_EQ(2, b_);
// failed EXPECT_THROW_MSG, throws an exception with different message // failed EXPECT_THROW_MSG, throws an exception with different message
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG({ // NOLINT EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(
{ // NOLINT
a_++; a_++;
throw_exception(); throw_exception();
}, std::exception, (b_++, "other")), },
std::exception, (b_++, "other")),
"throws an exception with a different message"); "throws an exception with a different message");
EXPECT_EQ(3, a_); EXPECT_EQ(3, a_);
EXPECT_EQ(3, b_); EXPECT_EQ(3, b_);
@ -120,33 +123,40 @@ TEST_F(SingleEvaluationTest, ExceptionTests) {
TEST_F(SingleEvaluationTest, SystemErrorTests) { TEST_F(SingleEvaluationTest, SystemErrorTests) {
// successful EXPECT_SYSTEM_ERROR // successful EXPECT_SYSTEM_ERROR
EXPECT_SYSTEM_ERROR({ // NOLINT EXPECT_SYSTEM_ERROR(
{ // NOLINT
a_++; a_++;
throw_system_error(); throw_system_error();
}, EDOM, (b_++, "test")); },
EDOM, (b_++, "test"));
EXPECT_EQ(1, a_); EXPECT_EQ(1, a_);
EXPECT_EQ(1, b_); EXPECT_EQ(1, b_);
// failed EXPECT_SYSTEM_ERROR, throws different type // failed EXPECT_SYSTEM_ERROR, throws different type
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR({ // NOLINT EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
{ // NOLINT
a_++; a_++;
throw_exception(); throw_exception();
}, EDOM, (b_++, "test")), "throws a different type"); },
EDOM, (b_++, "test")),
"throws a different type");
EXPECT_EQ(2, a_); EXPECT_EQ(2, a_);
EXPECT_EQ(2, b_); EXPECT_EQ(2, b_);
// failed EXPECT_SYSTEM_ERROR, throws an exception with different message // failed EXPECT_SYSTEM_ERROR, throws an exception with different message
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR({ // NOLINT EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
{ // NOLINT
a_++; a_++;
throw_system_error(); throw_system_error();
}, EDOM, (b_++, "other")), },
EDOM, (b_++, "other")),
"throws an exception with a different message"); "throws an exception with a different message");
EXPECT_EQ(3, a_); EXPECT_EQ(3, a_);
EXPECT_EQ(3, b_); EXPECT_EQ(3, b_);
// failed EXPECT_SYSTEM_ERROR, throws nothing // failed EXPECT_SYSTEM_ERROR, throws nothing
EXPECT_NONFATAL_FAILURE( EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(a_++, EDOM, (b_++, "test")),
EXPECT_SYSTEM_ERROR(a_++, EDOM, (b_++, "test")), "throws nothing"); "throws nothing");
EXPECT_EQ(4, a_); EXPECT_EQ(4, a_);
EXPECT_EQ(4, b_); EXPECT_EQ(4, b_);
} }
@ -154,18 +164,23 @@ TEST_F(SingleEvaluationTest, SystemErrorTests) {
// Tests that assertion arguments are evaluated exactly once. // Tests that assertion arguments are evaluated exactly once.
TEST_F(SingleEvaluationTest, WriteTests) { TEST_F(SingleEvaluationTest, WriteTests) {
// successful EXPECT_WRITE // successful EXPECT_WRITE
EXPECT_WRITE(stdout, { // NOLINT EXPECT_WRITE(stdout,
{ // NOLINT
a_++; a_++;
std::printf("test"); std::printf("test");
}, (b_++, "test")); },
(b_++, "test"));
EXPECT_EQ(1, a_); EXPECT_EQ(1, a_);
EXPECT_EQ(1, b_); EXPECT_EQ(1, b_);
// failed EXPECT_WRITE // failed EXPECT_WRITE
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, { // NOLINT EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout,
{ // NOLINT
a_++; a_++;
std::printf("test"); std::printf("test");
}, (b_++, "other")), "Actual: test"); },
(b_++, "other")),
"Actual: test");
EXPECT_EQ(2, a_); EXPECT_EQ(2, a_);
EXPECT_EQ(2, b_); EXPECT_EQ(2, b_);
} }
@ -178,8 +193,8 @@ TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) {
EXPECT_THROW_MSG(throw runtime_error(""), runtime_error, ""); EXPECT_THROW_MSG(throw runtime_error(""), runtime_error, "");
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(n++, 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 1, runtime_error, ""), "");
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG( EXPECT_NONFATAL_FAILURE(
throw runtime_error("a"), runtime_error, "b"), ""); EXPECT_THROW_MSG(throw runtime_error("a"), runtime_error, "b"), "");
} }
// Tests that the compiler will not complain about unreachable code in the // Tests that the compiler will not complain about unreachable code in the
@ -189,8 +204,9 @@ TEST(ExpectSystemErrorTest, DoesNotGenerateUnreachableCodeWarning) {
EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "test"), EDOM, "test"); 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(n++, EDOM, ""), "");
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw 1, EDOM, ""), ""); EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw 1, EDOM, ""), "");
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR( EXPECT_NONFATAL_FAILURE(
throw fmt::system_error(EDOM, "aaa"), EDOM, "bbb"), ""); EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "aaa"), EDOM, "bbb"),
"");
} }
TEST(AssertionSyntaxTest, ExceptionAssertionBehavesLikeSingleStatement) { TEST(AssertionSyntaxTest, ExceptionAssertionBehavesLikeSingleStatement) {
@ -267,8 +283,7 @@ TEST(ExpectTest, EXPECT_WRITE) {
EXPECT_WRITE(stdout, do_nothing(), ""); EXPECT_WRITE(stdout, do_nothing(), "");
EXPECT_WRITE(stdout, std::printf("test"), "test"); EXPECT_WRITE(stdout, std::printf("test"), "test");
EXPECT_WRITE(stderr, std::fprintf(stderr, "test"), "test"); EXPECT_WRITE(stderr, std::fprintf(stderr, "test"), "test");
EXPECT_NONFATAL_FAILURE( EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("that"), "this"),
EXPECT_WRITE(stdout, std::printf("that"), "this"),
"Expected: this\n" "Expected: this\n"
" Actual: that"); " Actual: that");
} }
@ -278,7 +293,8 @@ TEST(StreamingAssertionsTest, EXPECT_THROW_MSG) {
<< "unexpected failure"; << "unexpected failure";
EXPECT_NONFATAL_FAILURE( EXPECT_NONFATAL_FAILURE(
EXPECT_THROW_MSG(throw_exception(), std::exception, "other") EXPECT_THROW_MSG(throw_exception(), std::exception, "other")
<< "expected failure", "expected failure"); << "expected failure",
"expected failure");
} }
TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) { TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) {
@ -286,15 +302,15 @@ TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) {
<< "unexpected failure"; << "unexpected failure";
EXPECT_NONFATAL_FAILURE( EXPECT_NONFATAL_FAILURE(
EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other") EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other")
<< "expected failure", "expected failure"); << "expected failure",
"expected failure");
} }
TEST(StreamingAssertionsTest, EXPECT_WRITE) { TEST(StreamingAssertionsTest, EXPECT_WRITE) {
EXPECT_WRITE(stdout, std::printf("test"), "test") EXPECT_WRITE(stdout, std::printf("test"), "test") << "unexpected failure";
<< "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), "other")
EXPECT_NONFATAL_FAILURE( << "expected failure",
EXPECT_WRITE(stdout, std::printf("test"), "other") "expected failure");
<< "expected failure", "expected failure");
} }
TEST(UtilTest, FormatSystemError) { TEST(UtilTest, FormatSystemError) {
@ -340,8 +356,8 @@ TEST(OutputRedirectTest, FlushErrorInCtor) {
EXPECT_EQ('x', fputc('x', f.get())); EXPECT_EQ('x', fputc('x', f.get()));
FMT_POSIX(close(write_fd)); FMT_POSIX(close(write_fd));
std::unique_ptr<OutputRedirect> redir{FMT_NULL}; std::unique_ptr<OutputRedirect> redir{FMT_NULL};
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())), EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())), EBADF,
EBADF, "cannot flush stream"); "cannot flush stream");
redir.reset(FMT_NULL); redir.reset(FMT_NULL);
write_copy.dup2(write_fd); // "undo" close or dtor will fail write_copy.dup2(write_fd); // "undo" close or dtor will fail
} }
@ -352,8 +368,9 @@ TEST(OutputRedirectTest, DupErrorInCtor) {
file copy = file::dup(fd); file copy = file::dup(fd);
FMT_POSIX(close(fd)); FMT_POSIX(close(fd));
std::unique_ptr<OutputRedirect> redir{FMT_NULL}; std::unique_ptr<OutputRedirect> redir{FMT_NULL};
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())), EXPECT_SYSTEM_ERROR_NOASSERT(
EBADF, fmt::format("cannot duplicate file descriptor {}", fd)); redir.reset(new OutputRedirect(f.get())), EBADF,
fmt::format("cannot duplicate file descriptor {}", fd));
copy.dup2(fd); // "undo" close or dtor will fail copy.dup2(fd); // "undo" close or dtor will fail
} }
@ -382,8 +399,8 @@ TEST(OutputRedirectTest, FlushErrorInRestoreAndRead) {
// Put a character in a file buffer. // Put a character in a file buffer.
EXPECT_EQ('x', fputc('x', f.get())); EXPECT_EQ('x', fputc('x', f.get()));
FMT_POSIX(close(write_fd)); FMT_POSIX(close(write_fd));
EXPECT_SYSTEM_ERROR_NOASSERT(redir.restore_and_read(), EXPECT_SYSTEM_ERROR_NOASSERT(redir.restore_and_read(), EBADF,
EBADF, "cannot flush stream"); "cannot flush stream");
write_copy.dup2(write_fd); // "undo" close or dtor will fail write_copy.dup2(write_fd); // "undo" close or dtor will fail
} }
@ -396,14 +413,16 @@ TEST(OutputRedirectTest, ErrorInDtor) {
std::unique_ptr<OutputRedirect> redir(new OutputRedirect(f.get())); std::unique_ptr<OutputRedirect> redir(new OutputRedirect(f.get()));
// Put a character in a file buffer. // Put a character in a file buffer.
EXPECT_EQ('x', fputc('x', f.get())); EXPECT_EQ('x', fputc('x', f.get()));
EXPECT_WRITE(stderr, { EXPECT_WRITE(stderr,
// The close function must be called inside EXPECT_WRITE, otherwise {
// the system may recycle closed file descriptor when redirecting the // The close function must be called inside EXPECT_WRITE,
// output in EXPECT_STDERR and the second close will break output // otherwise the system may recycle closed file descriptor when
// redirection. // redirecting the output in EXPECT_STDERR and the second close
// will break output redirection.
FMT_POSIX(close(write_fd)); FMT_POSIX(close(write_fd));
SUPPRESS_ASSERT(redir.reset(FMT_NULL)); SUPPRESS_ASSERT(redir.reset(FMT_NULL));
}, format_system_error(EBADF, "cannot flush stream")); },
format_system_error(EBADF, "cannot flush stream"));
write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail
} }

View File

@ -17,13 +17,11 @@ void OutputRedirect::flush() {
# endif # endif
int result = 0; int result = 0;
FMT_RETRY(result, fflush(file_)); FMT_RETRY(result, fflush(file_));
if (result != 0) if (result != 0) throw fmt::system_error(errno, "cannot flush stream");
throw fmt::system_error(errno, "cannot flush stream");
} }
void OutputRedirect::restore() { void OutputRedirect::restore() {
if (original_.descriptor() == -1) if (original_.descriptor() == -1) return; // Already restored.
return; // Already restored.
flush(); flush();
// Restore the original file. // Restore the original file.
original_.dup2(FMT_POSIX(fileno(file_))); original_.dup2(FMT_POSIX(fileno(file_)));
@ -56,8 +54,7 @@ std::string OutputRedirect::restore_and_read() {
// Read everything from the pipe. // Read everything from the pipe.
std::string content; std::string content;
if (read_end_.descriptor() == -1) if (read_end_.descriptor() == -1) return content; // Already read.
return content; // Already read.
enum { BUFFER_SIZE = 4096 }; enum { BUFFER_SIZE = 4096 };
char buffer[BUFFER_SIZE]; char buffer[BUFFER_SIZE];
std::size_t count = 0; std::size_t count = 0;

View File

@ -28,38 +28,36 @@
bool gtest_caught_expected = false; \ bool gtest_caught_expected = false; \
try { \ try { \
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
} \ } catch (expected_exception const& e) { \
catch (expected_exception const& e) { \
if (gtest_expected_message != e.what()) { \ if (gtest_expected_message != e.what()) { \
gtest_ar \ gtest_ar << #statement \
<< #statement " throws an exception with a different message.\n" \ " throws an exception with a different message.\n" \
<< "Expected: " << gtest_expected_message << "\n" \ << "Expected: " << gtest_expected_message << "\n" \
<< " Actual: " << e.what(); \ << " Actual: " << e.what(); \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \ } \
gtest_caught_expected = true; \ gtest_caught_expected = true; \
} \ } catch (...) { \
catch (...) { \ gtest_ar << "Expected: " #statement \
gtest_ar << \ " throws an exception of type " #expected_exception \
"Expected: " #statement " throws an exception of type " \ ".\n Actual: it throws a different type."; \
#expected_exception ".\n Actual: it throws a different type."; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \ } \
if (!gtest_caught_expected) { \ if (!gtest_caught_expected) { \
gtest_ar << \ gtest_ar << "Expected: " #statement \
"Expected: " #statement " throws an exception of type " \ " throws an exception of type " #expected_exception \
#expected_exception ".\n Actual: it throws nothing."; \ ".\n Actual: it throws nothing."; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \ } \
} else \ } else \
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
fail(gtest_ar.failure_message()) : fail(gtest_ar.failure_message())
// Tests that the statement throws the expected exception and the exception's // Tests that the statement throws the expected exception and the exception's
// what() method returns expected message. // what() method returns expected message.
#define EXPECT_THROW_MSG(statement, expected_exception, expected_message) \ #define EXPECT_THROW_MSG(statement, expected_exception, expected_message) \
FMT_TEST_THROW_(statement, expected_exception, \ FMT_TEST_THROW_(statement, expected_exception, expected_message, \
expected_message, GTEST_NONFATAL_FAILURE_) GTEST_NONFATAL_FAILURE_)
std::string format_system_error(int error_code, fmt::string_view message); std::string format_system_error(int error_code, fmt::string_view message);
@ -99,15 +97,14 @@ class OutputRedirect {
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
std::string gtest_output = gtest_redir.restore_and_read(); \ std::string gtest_output = gtest_redir.restore_and_read(); \
if (gtest_output != gtest_expected_output) { \ if (gtest_output != gtest_expected_output) { \
gtest_ar \ gtest_ar << #statement " produces different output.\n" \
<< #statement " produces different output.\n" \
<< "Expected: " << gtest_expected_output << "\n" \ << "Expected: " << gtest_expected_output << "\n" \
<< " Actual: " << gtest_output; \ << " Actual: " << gtest_output; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \ } \
} else \ } else \
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
fail(gtest_ar.failure_message()) : fail(gtest_ar.failure_message())
// Tests that the statement writes the expected output to file. // Tests that the statement writes the expected output to file.
# define EXPECT_WRITE(file, statement, expected_output) \ # define EXPECT_WRITE(file, statement, expected_output) \
@ -122,21 +119,25 @@ class SuppressAssert {
_invalid_parameter_handler original_handler_; _invalid_parameter_handler original_handler_;
int original_report_mode_; int original_report_mode_;
static void handle_invalid_parameter(const wchar_t *, static void handle_invalid_parameter(const wchar_t*, const wchar_t*,
const wchar_t *, const wchar_t *, unsigned , uintptr_t) {} const wchar_t*, unsigned, uintptr_t) {}
public: public:
SuppressAssert() SuppressAssert()
: original_handler_(_set_invalid_parameter_handler(handle_invalid_parameter)), : original_handler_(
original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) { _set_invalid_parameter_handler(handle_invalid_parameter)),
} original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) {}
~SuppressAssert() { ~SuppressAssert() {
_set_invalid_parameter_handler(original_handler_); _set_invalid_parameter_handler(original_handler_);
_CrtSetReportMode(_CRT_ASSERT, original_report_mode_); _CrtSetReportMode(_CRT_ASSERT, original_report_mode_);
} }
}; };
# define SUPPRESS_ASSERT(statement) { SuppressAssert sa; statement; } # define SUPPRESS_ASSERT(statement) \
{ \
SuppressAssert sa; \
statement; \
}
# else # else
# define SUPPRESS_ASSERT(statement) statement # define SUPPRESS_ASSERT(statement) statement
# endif // _MSC_VER # endif // _MSC_VER
@ -152,8 +153,7 @@ std::string read(fmt::file &f, std::size_t count);
#endif // FMT_USE_FILE_DESCRIPTORS #endif // FMT_USE_FILE_DESCRIPTORS
template <typename Mock> template <typename Mock> struct ScopedMock : testing::StrictMock<Mock> {
struct ScopedMock : testing::StrictMock<Mock> {
ScopedMock() { Mock::instance = this; } ScopedMock() { Mock::instance = this; }
~ScopedMock() { Mock::instance = FMT_NULL; } ~ScopedMock() { Mock::instance = FMT_NULL; }
}; };

View File

@ -8,8 +8,7 @@
#include "fmt/locale.h" #include "fmt/locale.h"
#include "gmock.h" #include "gmock.h"
template <typename Char> template <typename Char> struct numpunct : std::numpunct<Char> {
struct numpunct : std::numpunct<Char> {
protected: protected:
Char do_thousands_sep() const FMT_OVERRIDE { return '~'; } Char do_thousands_sep() const FMT_OVERRIDE { return '~'; }
}; };

View File

@ -8,11 +8,10 @@
#ifndef FMT_MOCK_ALLOCATOR_H_ #ifndef FMT_MOCK_ALLOCATOR_H_
#define FMT_MOCK_ALLOCATOR_H_ #define FMT_MOCK_ALLOCATOR_H_
#include "gmock.h"
#include "fmt/format.h" #include "fmt/format.h"
#include "gmock.h"
template <typename T> template <typename T> class mock_allocator {
class mock_allocator {
public: public:
mock_allocator() {} mock_allocator() {}
mock_allocator(const mock_allocator&) {} mock_allocator(const mock_allocator&) {}
@ -21,8 +20,7 @@ class mock_allocator {
MOCK_METHOD2_T(deallocate, void(T* p, std::size_t n)); MOCK_METHOD2_T(deallocate, void(T* p, std::size_t n));
}; };
template <typename Allocator> template <typename Allocator> class allocator_ref {
class allocator_ref {
private: private:
Allocator* alloc_; Allocator* alloc_;

View File

@ -75,20 +75,20 @@ TEST(OStreamTest, Format) {
TEST(OStreamTest, FormatSpecs) { TEST(OStreamTest, FormatSpecs) {
EXPECT_EQ("def ", format("{0:<5}", TestString("def"))); EXPECT_EQ("def ", format("{0:<5}", TestString("def")));
EXPECT_EQ(" def", format("{0:>5}", TestString("def"))); EXPECT_EQ(" def", format("{0:>5}", TestString("def")));
EXPECT_THROW_MSG(format("{0:=5}", TestString("def")), EXPECT_THROW_MSG(format("{0:=5}", TestString("def")), format_error,
format_error, "format specifier requires numeric argument"); "format specifier requires numeric argument");
EXPECT_EQ(" def ", format("{0:^5}", TestString("def"))); EXPECT_EQ(" def ", format("{0:^5}", TestString("def")));
EXPECT_EQ("def**", format("{0:*<5}", TestString("def"))); EXPECT_EQ("def**", format("{0:*<5}", TestString("def")));
EXPECT_THROW_MSG(format("{0:+}", TestString()), EXPECT_THROW_MSG(format("{0:+}", TestString()), format_error,
format_error, "format specifier requires numeric argument"); "format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:-}", TestString()), EXPECT_THROW_MSG(format("{0:-}", TestString()), format_error,
format_error, "format specifier requires numeric argument"); "format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0: }", TestString()), EXPECT_THROW_MSG(format("{0: }", TestString()), format_error,
format_error, "format specifier requires numeric argument"); "format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:#}", TestString()), EXPECT_THROW_MSG(format("{0:#}", TestString()), format_error,
format_error, "format specifier requires numeric argument"); "format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:05}", TestString()), EXPECT_THROW_MSG(format("{0:05}", TestString()), format_error,
format_error, "format specifier requires numeric argument"); "format specifier requires numeric argument");
EXPECT_EQ("test ", format("{0:13}", TestString("test"))); EXPECT_EQ("test ", format("{0:13}", TestString("test")));
EXPECT_EQ("test ", format("{0:{1}}", TestString("test"), 13)); EXPECT_EQ("test ", format("{0:{1}}", TestString("test"), 13));
EXPECT_EQ("te", format("{0:.2}", TestString("test"))); EXPECT_EQ("te", format("{0:.2}", TestString("test")));
@ -125,8 +125,7 @@ TEST(OStreamTest, WriteToOStream) {
TEST(OStreamTest, WriteToOStreamMaxSize) { TEST(OStreamTest, WriteToOStreamMaxSize) {
std::size_t max_size = std::numeric_limits<std::size_t>::max(); std::size_t max_size = std::numeric_limits<std::size_t>::max();
std::streamsize max_streamsize = std::numeric_limits<std::streamsize>::max(); std::streamsize max_streamsize = std::numeric_limits<std::streamsize>::max();
if (max_size <= fmt::internal::to_unsigned(max_streamsize)) if (max_size <= fmt::internal::to_unsigned(max_streamsize)) return;
return;
struct test_buffer : fmt::internal::buffer { struct test_buffer : fmt::internal::buffer {
explicit test_buffer(std::size_t size) { resize(size); } explicit test_buffer(std::size_t size) { resize(size); }

View File

@ -13,9 +13,9 @@
#include "posix-mock.h" #include "posix-mock.h"
#include "../src/posix.cc" #include "../src/posix.cc"
#include <climits>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <climits>
#include <memory> #include <memory>
#ifdef _WIN32 #ifdef _WIN32
@ -33,8 +33,8 @@ using fmt::error_code;
using fmt::file; using fmt::file;
using testing::_; using testing::_;
using testing::StrEq;
using testing::Return; using testing::Return;
using testing::StrEq;
namespace { namespace {
int open_count; int open_count;
@ -53,7 +53,7 @@ std::size_t write_nbyte;
bool sysconf_error; bool sysconf_error;
enum FStatSimulation { NONE, MAX_SIZE, ERROR } fstat_sim; enum FStatSimulation { NONE, MAX_SIZE, ERROR } fstat_sim;
} } // namespace
#define EMULATE_EINTR(func, error_result) \ #define EMULATE_EINTR(func, error_result) \
if (func##_count != 0) { \ if (func##_count != 0) { \
@ -69,8 +69,8 @@ int test::open(const char *path, int oflag, int mode) {
return ::open(path, oflag, mode); return ::open(path, oflag, mode);
} }
#else #else
errno_t test::sopen_s( errno_t test::sopen_s(int* pfh, const char* filename, int oflag, int shflag,
int* pfh, const char *filename, int oflag, int shflag, int pmode) { int pmode) {
EMULATE_EINTR(open, EINTR); EMULATE_EINTR(open, EINTR);
return _sopen_s(pfh, filename, oflag, shflag, pmode); return _sopen_s(pfh, filename, oflag, shflag, pmode);
} }
@ -80,8 +80,7 @@ errno_t test::sopen_s(
long test::sysconf(int name) { long test::sysconf(int name) {
long result = ::sysconf(name); long result = ::sysconf(name);
if (!sysconf_error) if (!sysconf_error) return result;
return result;
// Simulate an error. // Simulate an error.
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@ -91,8 +90,7 @@ static off_t max_file_size() { return std::numeric_limits<off_t>::max(); }
int test::fstat(int fd, struct stat* buf) { int test::fstat(int fd, struct stat* buf) {
int result = ::fstat(fd, buf); int result = ::fstat(fd, buf);
if (fstat_sim == MAX_SIZE) if (fstat_sim == MAX_SIZE) buf->st_size = max_file_size();
buf->st_size = max_file_size();
return result; return result;
} }
@ -208,8 +206,8 @@ TEST(UtilTest, GetPageSize) {
#else #else
EXPECT_EQ(sysconf(_SC_PAGESIZE), fmt::getpagesize()); EXPECT_EQ(sysconf(_SC_PAGESIZE), fmt::getpagesize());
sysconf_error = true; sysconf_error = true;
EXPECT_SYSTEM_ERROR( EXPECT_SYSTEM_ERROR(fmt::getpagesize(), EINVAL,
fmt::getpagesize(), EINVAL, "cannot get memory page size"); "cannot get memory page size");
sysconf_error = false; sysconf_error = false;
#endif #endif
} }
@ -217,8 +215,8 @@ TEST(UtilTest, GetPageSize) {
TEST(FileTest, OpenRetry) { TEST(FileTest, OpenRetry) {
write_file("test", "there must be something here"); write_file("test", "there must be something here");
std::unique_ptr<file> f{FMT_NULL}; std::unique_ptr<file> f{FMT_NULL};
EXPECT_RETRY(f.reset(new file("test", file::RDONLY)), EXPECT_RETRY(f.reset(new file("test", file::RDONLY)), open,
open, "cannot open file test"); "cannot open file test");
#ifndef _WIN32 #ifndef _WIN32
char c = 0; char c = 0;
f->read(&c, 1); f->read(&c, 1);
@ -230,12 +228,14 @@ TEST(FileTest, CloseNoRetryInDtor) {
file::pipe(read_end, write_end); file::pipe(read_end, write_end);
std::unique_ptr<file> f(new file(std::move(read_end))); std::unique_ptr<file> f(new file(std::move(read_end)));
int saved_close_count = 0; int saved_close_count = 0;
EXPECT_WRITE(stderr, { EXPECT_WRITE(stderr,
{
close_count = 1; close_count = 1;
f.reset(FMT_NULL); f.reset(FMT_NULL);
saved_close_count = close_count; saved_close_count = close_count;
close_count = 0; close_count = 0;
}, format_system_error(EINTR, "cannot close file") + "\n"); },
format_system_error(EINTR, "cannot close file") + "\n");
EXPECT_EQ(2, saved_close_count); EXPECT_EQ(2, saved_close_count);
} }
@ -256,8 +256,8 @@ TEST(FileTest, Size) {
EXPECT_EQ(content.size(), static_cast<unsigned long long>(f.size())); EXPECT_EQ(content.size(), static_cast<unsigned long long>(f.size()));
#ifdef _WIN32 #ifdef _WIN32
fmt::memory_buffer message; fmt::memory_buffer message;
fmt::internal::format_windows_error( fmt::internal::format_windows_error(message, ERROR_ACCESS_DENIED,
message, ERROR_ACCESS_DENIED, "cannot get file size"); "cannot get file size");
fstat_sim = ERROR; fstat_sim = ERROR;
EXPECT_THROW_MSG(f.size(), fmt::windows_error, fmt::to_string(message)); EXPECT_THROW_MSG(f.size(), fmt::windows_error, fmt::to_string(message));
fstat_sim = NONE; fstat_sim = NONE;
@ -284,8 +284,8 @@ TEST(FileTest, ReadRetry) {
write_end.close(); write_end.close();
char buffer[SIZE]; char buffer[SIZE];
std::size_t count = 0; std::size_t count = 0;
EXPECT_RETRY(count = read_end.read(buffer, SIZE), EXPECT_RETRY(count = read_end.read(buffer, SIZE), read,
read, "cannot read from file"); "cannot read from file");
EXPECT_EQ_POSIX(static_cast<std::streamsize>(SIZE), count); EXPECT_EQ_POSIX(static_cast<std::streamsize>(SIZE), count);
} }
@ -294,8 +294,8 @@ TEST(FileTest, WriteRetry) {
file::pipe(read_end, write_end); file::pipe(read_end, write_end);
enum { SIZE = 4 }; enum { SIZE = 4 };
std::size_t count = 0; std::size_t count = 0;
EXPECT_RETRY(count = write_end.write("test", SIZE), EXPECT_RETRY(count = write_end.write("test", SIZE), write,
write, "cannot write to file"); "cannot write to file");
write_end.close(); write_end.close();
#ifndef _WIN32 #ifndef _WIN32
EXPECT_EQ(static_cast<std::streamsize>(SIZE), count); EXPECT_EQ(static_cast<std::streamsize>(SIZE), count);
@ -312,8 +312,7 @@ TEST(FileTest, ConvertReadCount) {
file::pipe(read_end, write_end); file::pipe(read_end, write_end);
char c; char c;
std::size_t size = UINT_MAX; std::size_t size = UINT_MAX;
if (sizeof(unsigned) != sizeof(std::size_t)) if (sizeof(unsigned) != sizeof(std::size_t)) ++size;
++size;
read_count = 1; read_count = 1;
read_nbyte = 0; read_nbyte = 0;
EXPECT_THROW(read_end.read(&c, size), fmt::system_error); EXPECT_THROW(read_end.read(&c, size), fmt::system_error);
@ -326,8 +325,7 @@ TEST(FileTest, ConvertWriteCount) {
file::pipe(read_end, write_end); file::pipe(read_end, write_end);
char c; char c;
std::size_t size = UINT_MAX; std::size_t size = UINT_MAX;
if (sizeof(unsigned) != sizeof(std::size_t)) if (sizeof(unsigned) != sizeof(std::size_t)) ++size;
++size;
write_count = 1; write_count = 1;
write_nbyte = 0; write_nbyte = 0;
EXPECT_THROW(write_end.write(&c, size), fmt::system_error); EXPECT_THROW(write_end.write(&c, size), fmt::system_error);
@ -339,7 +337,8 @@ TEST(FileTest, ConvertWriteCount) {
TEST(FileTest, DupNoRetry) { TEST(FileTest, DupNoRetry) {
int stdout_fd = FMT_POSIX(fileno(stdout)); int stdout_fd = FMT_POSIX(fileno(stdout));
dup_count = 1; 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)); fmt::format("cannot duplicate file descriptor {}", stdout_fd));
dup_count = 0; dup_count = 0;
} }
@ -369,8 +368,8 @@ TEST(FileTest, Dup2NoExceptRetry) {
TEST(FileTest, PipeNoRetry) { TEST(FileTest, PipeNoRetry) {
file read_end, write_end; file read_end, write_end;
pipe_count = 1; pipe_count = 1;
EXPECT_SYSTEM_ERROR( EXPECT_SYSTEM_ERROR(file::pipe(read_end, write_end), EINTR,
file::pipe(read_end, write_end), EINTR, "cannot create pipe"); "cannot create pipe");
pipe_count = 0; pipe_count = 0;
} }
@ -378,16 +377,16 @@ TEST(FileTest, FdopenNoRetry) {
file read_end, write_end; file read_end, write_end;
file::pipe(read_end, write_end); file::pipe(read_end, write_end);
fdopen_count = 1; fdopen_count = 1;
EXPECT_SYSTEM_ERROR(read_end.fdopen("r"), EXPECT_SYSTEM_ERROR(read_end.fdopen("r"), EINTR,
EINTR, "cannot associate stream with file descriptor"); "cannot associate stream with file descriptor");
fdopen_count = 0; fdopen_count = 0;
} }
TEST(BufferedFileTest, OpenRetry) { TEST(BufferedFileTest, OpenRetry) {
write_file("test", "there must be something here"); write_file("test", "there must be something here");
std::unique_ptr<buffered_file> f{FMT_NULL}; std::unique_ptr<buffered_file> f{FMT_NULL};
EXPECT_RETRY(f.reset(new buffered_file("test", "r")), EXPECT_RETRY(f.reset(new buffered_file("test", "r")), fopen,
fopen, "cannot open file test"); "cannot open file test");
#ifndef _WIN32 #ifndef _WIN32
char c = 0; char c = 0;
if (fread(&c, 1, 1, f->get()) < 1) if (fread(&c, 1, 1, f->get()) < 1)
@ -400,12 +399,14 @@ TEST(BufferedFileTest, CloseNoRetryInDtor) {
file::pipe(read_end, write_end); file::pipe(read_end, write_end);
std::unique_ptr<buffered_file> f(new buffered_file(read_end.fdopen("r"))); std::unique_ptr<buffered_file> f(new buffered_file(read_end.fdopen("r")));
int saved_fclose_count = 0; int saved_fclose_count = 0;
EXPECT_WRITE(stderr, { EXPECT_WRITE(stderr,
{
fclose_count = 1; fclose_count = 1;
f.reset(FMT_NULL); f.reset(FMT_NULL);
saved_fclose_count = fclose_count; saved_fclose_count = fclose_count;
fclose_count = 0; fclose_count = 0;
}, format_system_error(EINTR, "cannot close file") + "\n"); },
format_system_error(EINTR, "cannot close file") + "\n");
EXPECT_EQ(2, saved_fclose_count); EXPECT_EQ(2, saved_fclose_count);
} }
@ -453,8 +454,8 @@ struct LocaleMock {
LocaleType base)); LocaleType base));
MOCK_METHOD1(freelocale, void(LocaleType locale)); MOCK_METHOD1(freelocale, void(LocaleType locale));
MOCK_METHOD3(strtod_l, double (const char *nptr, char **endptr, MOCK_METHOD3(strtod_l,
LocaleType locale)); double(const char* nptr, char** endptr, LocaleType locale));
} * LocaleMock::instance; } * LocaleMock::instance;
# ifdef _MSC_VER # ifdef _MSC_VER
@ -481,11 +482,13 @@ double _strtod_l(const char *nptr, char **endptr, _locale_t locale) {
# define FMT_LOCALE_THROW # define FMT_LOCALE_THROW
# endif # 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); return LocaleMock::instance->newlocale(category_mask, locale, base);
} }
#if defined(__APPLE__) || (defined(__FreeBSD__) && __FreeBSD_version < 1200002) # if defined(__APPLE__) || \
(defined(__FreeBSD__) && __FreeBSD_version < 1200002)
typedef int FreeLocaleResult; typedef int FreeLocaleResult;
# else # else
typedef void FreeLocaleResult; typedef void FreeLocaleResult;
@ -496,7 +499,8 @@ FreeLocaleResult freelocale(LocaleType locale) FMT_LOCALE_THROW {
return FreeLocaleResult(); 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); return LocaleMock::instance->strtod_l(nptr, endptr, locale);
} }

View File

@ -33,8 +33,8 @@ int fstat(int fd, struct stat *buf);
#else #else
typedef unsigned size_t; typedef unsigned size_t;
typedef int ssize_t; typedef int ssize_t;
errno_t sopen_s( errno_t sopen_s(int* pfh, const char* filename, int oflag, int shflag,
int* pfh, const char *filename, int oflag, int shflag, int pmode); int pmode);
#endif #endif
#ifndef _WIN32 #ifndef _WIN32

View File

@ -119,14 +119,16 @@ TEST(BufferedFileTest, CloseFileInDtor) {
TEST(BufferedFileTest, CloseErrorInDtor) { TEST(BufferedFileTest, CloseErrorInDtor) {
std::unique_ptr<buffered_file> f(new buffered_file(open_buffered_file())); std::unique_ptr<buffered_file> f(new buffered_file(open_buffered_file()));
EXPECT_WRITE(stderr, { EXPECT_WRITE(stderr,
// The close function must be called inside EXPECT_WRITE, otherwise {
// the system may recycle closed file descriptor when redirecting the // The close function must be called inside EXPECT_WRITE,
// output in EXPECT_STDERR and the second close will break output // otherwise the system may recycle closed file descriptor when
// redirection. // redirecting the output in EXPECT_STDERR and the second close
// will break output redirection.
FMT_POSIX(close(f->fileno())); FMT_POSIX(close(f->fileno()));
SUPPRESS_ASSERT(f.reset(FMT_NULL)); SUPPRESS_ASSERT(f.reset(FMT_NULL));
}, format_system_error(EBADF, "cannot close file") + "\n"); },
format_system_error(EBADF, "cannot close file") + "\n");
} }
TEST(BufferedFileTest, Close) { TEST(BufferedFileTest, Close) {
@ -149,13 +151,15 @@ TEST(BufferedFileTest, Fileno) {
#ifndef __COVERITY__ #ifndef __COVERITY__
// fileno on a null FILE pointer either crashes or returns an error. // fileno on a null FILE pointer either crashes or returns an error.
// Disable Coverity because this is intentional. // Disable Coverity because this is intentional.
EXPECT_DEATH_IF_SUPPORTED({ EXPECT_DEATH_IF_SUPPORTED(
{
try { try {
f.fileno(); f.fileno();
} catch (const fmt::system_error&) { } catch (const fmt::system_error&) {
std::exit(1); std::exit(1);
} }
}, ""); },
"");
#endif #endif
f = open_buffered_file(); f = open_buffered_file();
EXPECT_TRUE(f.fileno() != -1); EXPECT_TRUE(f.fileno() != -1);
@ -177,8 +181,8 @@ TEST(FileTest, OpenBufferedFileInCtor) {
} }
TEST(FileTest, OpenBufferedFileError) { TEST(FileTest, OpenBufferedFileError) {
EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY), EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY), ENOENT,
ENOENT, "cannot open file nonexistent"); "cannot open file nonexistent");
} }
TEST(FileTest, MoveCtor) { TEST(FileTest, MoveCtor) {
@ -246,14 +250,16 @@ TEST(FileTest, CloseFileInDtor) {
TEST(FileTest, CloseErrorInDtor) { TEST(FileTest, CloseErrorInDtor) {
std::unique_ptr<file> f(new file(open_file())); std::unique_ptr<file> f(new file(open_file()));
EXPECT_WRITE(stderr, { EXPECT_WRITE(stderr,
// The close function must be called inside EXPECT_WRITE, otherwise {
// the system may recycle closed file descriptor when redirecting the // The close function must be called inside EXPECT_WRITE,
// output in EXPECT_STDERR and the second close will break output // otherwise the system may recycle closed file descriptor when
// redirection. // redirecting the output in EXPECT_STDERR and the second close
// will break output redirection.
FMT_POSIX(close(f->descriptor())); FMT_POSIX(close(f->descriptor()));
SUPPRESS_ASSERT(f.reset(FMT_NULL)); SUPPRESS_ASSERT(f.reset(FMT_NULL));
}, format_system_error(EBADF, "cannot close file") + "\n"); },
format_system_error(EBADF, "cannot close file") + "\n");
} }
TEST(FileTest, Close) { TEST(FileTest, Close) {
@ -309,8 +315,8 @@ TEST(FileTest, Dup) {
#ifndef __COVERITY__ #ifndef __COVERITY__
TEST(FileTest, DupError) { TEST(FileTest, DupError) {
int value = -1; int value = -1;
EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value), EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value), EBADF,
EBADF, "cannot duplicate file descriptor -1"); "cannot duplicate file descriptor -1");
} }
#endif #endif
@ -324,7 +330,8 @@ TEST(FileTest, Dup2) {
TEST(FileTest, Dup2Error) { TEST(FileTest, Dup2Error) {
file f = open_file(); file f = open_file();
EXPECT_SYSTEM_ERROR_NOASSERT(f.dup2(-1), EBADF, EXPECT_SYSTEM_ERROR_NOASSERT(
f.dup2(-1), EBADF,
fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor())); fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor()));
} }
@ -363,8 +370,8 @@ TEST(FileTest, Fdopen) {
TEST(FileTest, FdopenError) { TEST(FileTest, FdopenError) {
file f; file f;
EXPECT_SYSTEM_ERROR_NOASSERT( EXPECT_SYSTEM_ERROR_NOASSERT(f.fdopen("r"), EBADF,
f.fdopen("r"), EBADF, "cannot associate stream with file descriptor"); "cannot associate stream with file descriptor");
} }
#ifdef FMT_LOCALE #ifdef FMT_LOCALE

View File

@ -5,6 +5,7 @@
// //
// For the license information refer to prepare.h. // For the license information refer to prepare.h.
#include <stdint.h>
#include <cctype> #include <cctype>
#include <cfloat> #include <cfloat>
#include <climits> #include <climits>
@ -13,7 +14,6 @@
#include <deque> #include <deque>
#include <list> #include <list>
#include <memory> #include <memory>
#include <stdint.h>
#include <string> #include <string>
// Check if fmt/prepare.h compiles with windows.h included before it. // Check if fmt/prepare.h compiles with windows.h included before it.
@ -303,13 +303,15 @@ TEST(PrepareTest, FormatPreparationHandler_OnArgId_AddsPartWithPassedNamedId) {
const auto expected_third_arg_id = fmt::string_view(format.data() + 6, 3); const auto expected_third_arg_id = fmt::string_view(format.data() + 6, 3);
const auto expected_third_arg_view_metadata = const auto expected_third_arg_view_metadata =
fmt::internal::string_view_metadata(6, 3); fmt::internal::string_view_metadata(6, 3);
EXPECT_CALL(parts, add(format_part( EXPECT_CALL(
named_argument_id(expected_first_arg_view_metadata)))); parts,
add(format_part(named_argument_id(expected_first_arg_view_metadata))));
EXPECT_CALL( EXPECT_CALL(
parts, parts,
add(format_part(named_argument_id(expected_second_arg_view_metadata)))); add(format_part(named_argument_id(expected_second_arg_view_metadata))));
EXPECT_CALL(parts, add(format_part( EXPECT_CALL(
named_argument_id(expected_third_arg_view_metadata)))); parts,
add(format_part(named_argument_id(expected_third_arg_view_metadata))));
handler.on_arg_id(expected_first_arg_id); handler.on_arg_id(expected_first_arg_id);
handler.on_arg_id(expected_second_arg_id); handler.on_arg_id(expected_second_arg_id);

View File

@ -72,8 +72,7 @@ TEST(PrintfTest, PositionalArgs) {
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("before 42 after", test_sprintf("before %1$d after", 42));
EXPECT_EQ("answer = 42", test_sprintf("%1$s = %2$d", "answer", 42)); EXPECT_EQ("answer = 42", test_sprintf("%1$s = %2$d", "answer", 42));
EXPECT_EQ("42 is the answer", EXPECT_EQ("42 is the answer", test_sprintf("%2$d is the %1$s", "answer", 42));
test_sprintf("%2$d is the %1$s", "answer", 42));
EXPECT_EQ("abracadabra", test_sprintf("%1$s%2$s%1$s", "abra", "cad")); EXPECT_EQ("abracadabra", test_sprintf("%1$s%2$s%1$s", "abra", "cad"));
} }
@ -82,26 +81,26 @@ TEST(PrintfTest, AutomaticArgIndexing) {
} }
TEST(PrintfTest, NumberIsTooBigInArgIndex) { TEST(PrintfTest, NumberIsTooBigInArgIndex) {
EXPECT_THROW_MSG(test_sprintf(format("%{}$", BIG_NUM)), EXPECT_THROW_MSG(test_sprintf(format("%{}$", BIG_NUM)), format_error,
format_error, "number is too big"); "number is too big");
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM)), EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM)), format_error,
format_error, "number is too big"); "number is too big");
} }
TEST(PrintfTest, SwitchArgIndexing) { TEST(PrintfTest, SwitchArgIndexing) {
EXPECT_THROW_MSG(test_sprintf("%1$d%", 1, 2), EXPECT_THROW_MSG(test_sprintf("%1$d%", 1, 2), format_error,
format_error, "cannot switch from manual to automatic argument indexing"); "cannot switch from manual to automatic argument indexing");
EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2), EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
format_error, "number is too big"); format_error, "number is too big");
EXPECT_THROW_MSG(test_sprintf("%1$d%d", 1, 2), EXPECT_THROW_MSG(test_sprintf("%1$d%d", 1, 2), format_error,
format_error, "cannot switch from manual to automatic argument indexing"); "cannot switch from manual to automatic argument indexing");
EXPECT_THROW_MSG(test_sprintf("%d%1$", 1, 2), EXPECT_THROW_MSG(test_sprintf("%d%1$", 1, 2), format_error,
format_error, "cannot switch from automatic to manual argument indexing"); "cannot switch from automatic to manual argument indexing");
EXPECT_THROW_MSG(test_sprintf(format("%d%{}$d", BIG_NUM), 1, 2), EXPECT_THROW_MSG(test_sprintf(format("%d%{}$d", BIG_NUM), 1, 2), format_error,
format_error, "number is too big"); "number is too big");
EXPECT_THROW_MSG(test_sprintf("%d%1$d", 1, 2), EXPECT_THROW_MSG(test_sprintf("%d%1$d", 1, 2), format_error,
format_error, "cannot switch from automatic to manual argument indexing"); "cannot switch from automatic to manual argument indexing");
// Indexing errors override width errors. // Indexing errors override width errors.
EXPECT_THROW_MSG(test_sprintf(format("%d%1${}d", BIG_NUM), 1, 2), EXPECT_THROW_MSG(test_sprintf(format("%d%1${}d", BIG_NUM), 1, 2),
@ -115,13 +114,13 @@ TEST(PrintfTest, InvalidArgIndex) {
"argument index out of range"); "argument index out of range");
EXPECT_THROW_MSG(test_sprintf("%2$d", 42), format_error, EXPECT_THROW_MSG(test_sprintf("%2$d", 42), format_error,
"argument index out of range"); "argument index out of range");
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", INT_MAX), 42), EXPECT_THROW_MSG(test_sprintf(format("%{}$d", INT_MAX), 42), format_error,
format_error, "argument index out of range"); "argument index out of range");
EXPECT_THROW_MSG(test_sprintf("%2$", 42), EXPECT_THROW_MSG(test_sprintf("%2$", 42), format_error,
format_error, "argument index out of range"); "argument index out of range");
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM), 42), EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM), 42), format_error,
format_error, "number is too big"); "number is too big");
} }
TEST(PrintfTest, DefaultAlignRight) { TEST(PrintfTest, DefaultAlignRight) {
@ -175,8 +174,8 @@ TEST(PrintfTest, HashFlag) {
EXPECT_PRINTF("0x42", "%#x", 0x42); EXPECT_PRINTF("0x42", "%#x", 0x42);
EXPECT_PRINTF("0X42", "%#X", 0x42); EXPECT_PRINTF("0X42", "%#X", 0x42);
EXPECT_PRINTF( EXPECT_PRINTF(fmt::format("0x{:x}", static_cast<unsigned>(-0x42)), "%#x",
fmt::format("0x{:x}", static_cast<unsigned>(-0x42)), "%#x", -0x42); -0x42);
EXPECT_PRINTF("0", "%#x", 0); EXPECT_PRINTF("0", "%#x", 0);
EXPECT_PRINTF("0x0042", "%#06x", 0x42); EXPECT_PRINTF("0x0042", "%#06x", 0x42);
@ -210,10 +209,10 @@ TEST(PrintfTest, Width) {
EXPECT_THROW_MSG(test_sprintf("%5-5d", 42), format_error, EXPECT_THROW_MSG(test_sprintf("%5-5d", 42), format_error,
"invalid type specifier"); "invalid type specifier");
EXPECT_THROW_MSG(test_sprintf(format("%{}d", BIG_NUM), 42), EXPECT_THROW_MSG(test_sprintf(format("%{}d", BIG_NUM), 42), format_error,
format_error, "number is too big"); "number is too big");
EXPECT_THROW_MSG(test_sprintf(format("%1${}d", BIG_NUM), 42), EXPECT_THROW_MSG(test_sprintf(format("%1${}d", BIG_NUM), 42), format_error,
format_error, "number is too big"); "number is too big");
} }
TEST(PrintfTest, DynamicWidth) { TEST(PrintfTest, DynamicWidth) {
@ -279,12 +278,10 @@ TEST(PrintfTest, DynamicPrecision) {
} }
} }
template <typename T> template <typename T> struct make_signed { typedef T type; };
struct make_signed { typedef T type; };
#define SPECIALIZE_MAKE_SIGNED(T, S) \ #define SPECIALIZE_MAKE_SIGNED(T, S) \
template <> \ template <> struct make_signed<T> { typedef S type; }
struct make_signed<T> { typedef S type; }
SPECIALIZE_MAKE_SIGNED(char, signed char); SPECIALIZE_MAKE_SIGNED(char, signed char);
SPECIALIZE_MAKE_SIGNED(unsigned char, signed char); SPECIALIZE_MAKE_SIGNED(unsigned char, signed char);
@ -335,8 +332,7 @@ void TestLength(const char *length_spec, U value) {
EXPECT_PRINTF(os.str(), fmt::format("%{}X", length_spec), value); EXPECT_PRINTF(os.str(), fmt::format("%{}X", length_spec), value);
} }
template <typename T> template <typename T> void TestLength(const char* length_spec) {
void TestLength(const char *length_spec) {
T min = std::numeric_limits<T>::min(), max = std::numeric_limits<T>::max(); T min = std::numeric_limits<T>::min(), max = std::numeric_limits<T>::max();
TestLength<T>(length_spec, 42); TestLength<T>(length_spec, 42);
TestLength<T>(length_spec, -42); TestLength<T>(length_spec, -42);
@ -475,9 +471,7 @@ TEST(PrintfTest, Location) {
enum E { A = 42 }; enum E { A = 42 };
TEST(PrintfTest, Enum) { TEST(PrintfTest, Enum) { EXPECT_PRINTF("42", "%d", A); }
EXPECT_PRINTF("42", "%d", A);
}
#if FMT_USE_FILE_DESCRIPTORS #if FMT_USE_FILE_DESCRIPTORS
TEST(PrintfTest, Examples) { TEST(PrintfTest, Examples) {
@ -496,9 +490,7 @@ TEST(PrintfTest, PrintfError) {
} }
#endif #endif
TEST(PrintfTest, WideString) { TEST(PrintfTest, WideString) { EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc")); }
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc"));
}
TEST(PrintfTest, PrintfCustom) { TEST(PrintfTest, PrintfCustom) {
EXPECT_EQ("abc", test_sprintf("%s", TestString("abc"))); EXPECT_EQ("abc", test_sprintf("%s", TestString("abc")));
@ -530,21 +522,19 @@ TEST(PrintfTest, CheckFormatStringRegression) {
} }
TEST(PrintfTest, VSPrintfMakeArgsExample) { TEST(PrintfTest, VSPrintfMakeArgsExample) {
fmt::format_arg_store<fmt::printf_context, int, const char *> as{ fmt::format_arg_store<fmt::printf_context, int, const char*> as{42,
42, "something"}; "something"};
fmt::basic_format_args<fmt::printf_context> args(as); fmt::basic_format_args<fmt::printf_context> args(as);
EXPECT_EQ( EXPECT_EQ("[42] something happened", fmt::vsprintf("[%d] %s happened", args));
"[42] something happened", fmt::vsprintf("[%d] %s happened", args));
auto as2 = fmt::make_printf_args(42, "something"); auto as2 = fmt::make_printf_args(42, "something");
fmt::basic_format_args<fmt::printf_context> args2(as2); fmt::basic_format_args<fmt::printf_context> args2(as2);
EXPECT_EQ( EXPECT_EQ("[42] something happened",
"[42] something happened", fmt::vsprintf("[%d] %s happened", args2)); fmt::vsprintf("[%d] %s happened", args2));
// the older gcc versions can't cast the return value // the older gcc versions can't cast the return value
#if !defined(__GNUC__) || (__GNUC__ > 4) #if !defined(__GNUC__) || (__GNUC__ > 4)
EXPECT_EQ( EXPECT_EQ("[42] something happened",
"[42] something happened", fmt::vsprintf("[%d] %s happened",
fmt::vsprintf( fmt::make_printf_args(42, "something")));
"[%d] %s happened", fmt::make_printf_args(42, "something")));
#endif #endif
} }
@ -552,18 +542,16 @@ TEST(PrintfTest, VSPrintfMakeWArgsExample) {
fmt::format_arg_store<fmt::wprintf_context, int, const wchar_t*> as{ 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); fmt::basic_format_args<fmt::wprintf_context> args(as);
EXPECT_EQ( EXPECT_EQ(L"[42] something happened",
L"[42] something happened",
fmt::vsprintf(L"[%d] %s happened", args)); fmt::vsprintf(L"[%d] %s happened", args));
auto as2 = fmt::make_wprintf_args(42, L"something"); auto as2 = fmt::make_wprintf_args(42, L"something");
fmt::basic_format_args<fmt::wprintf_context> args2(as2); fmt::basic_format_args<fmt::wprintf_context> args2(as2);
EXPECT_EQ( EXPECT_EQ(L"[42] something happened",
L"[42] something happened", fmt::vsprintf(L"[%d] %s happened", args2)); fmt::vsprintf(L"[%d] %s happened", args2));
// the older gcc versions can't cast the return value // the older gcc versions can't cast the return value
#if !defined(__GNUC__) || (__GNUC__ > 4) #if !defined(__GNUC__) || (__GNUC__ > 4)
EXPECT_EQ( EXPECT_EQ(L"[42] something happened",
L"[42] something happened", fmt::vsprintf(L"[%d] %s happened",
fmt::vsprintf( fmt::make_wprintf_args(42, L"something")));
L"[%d] %s happened", fmt::make_wprintf_args(42, L"something")));
#endif #endif
} }

View File

@ -16,10 +16,10 @@
# include "fmt/ranges.h" # include "fmt/ranges.h"
# include "gtest.h" # include "gtest.h"
#include <vector>
# include <array> # include <array>
# include <map> # include <map>
# include <string> # include <string>
# include <vector>
TEST(RangesTest, FormatVector) { TEST(RangesTest, FormatVector) {
std::vector<int32_t> iv{1, 2, 3, 5, 7, 11}; std::vector<int32_t> iv{1, 2, 3, 5, 7, 11};
@ -52,8 +52,7 @@ TEST(RangesTest, FormatTuple) {
struct my_struct { struct my_struct {
int32_t i; int32_t i;
std::string str; // can throw std::string str; // can throw
template <std::size_t N> template <std::size_t N> decltype(auto) get() const noexcept {
decltype(auto) get() const noexcept {
if constexpr (N == 0) if constexpr (N == 0)
return i; return i;
else if constexpr (N == 1) else if constexpr (N == 1)
@ -61,8 +60,7 @@ struct my_struct {
} }
}; };
template <std::size_t N> template <std::size_t N> decltype(auto) get(const my_struct& s) noexcept {
decltype(auto) get(const my_struct& s) noexcept {
return s.get<N>(); return s.get<N>();
} }
@ -71,8 +69,7 @@ namespace std {
template <> template <>
struct tuple_size<my_struct> : std::integral_constant<std::size_t, 2> {}; struct tuple_size<my_struct> : std::integral_constant<std::size_t, 2> {};
template <std::size_t N> template <std::size_t N> struct tuple_element<N, my_struct> {
struct tuple_element<N, my_struct> {
using type = decltype(std::declval<my_struct>().get<N>()); using type = decltype(std::declval<my_struct>().get<N>());
}; };

View File

@ -9,9 +9,9 @@
# define _CRT_SECURE_NO_WARNINGS # define _CRT_SECURE_NO_WARNINGS
#endif #endif
#include "gmock.h"
#include "fmt/locale.h"
#include "fmt/time.h" #include "fmt/time.h"
#include "fmt/locale.h"
#include "gmock.h"
TEST(TimeTest, Format) { TEST(TimeTest, Format) {
std::tm tm = std::tm(); std::tm tm = std::tm();
@ -24,8 +24,7 @@ TEST(TimeTest, Format) {
TEST(TimeTest, GrowBuffer) { TEST(TimeTest, GrowBuffer) {
std::string s = "{:"; std::string s = "{:";
for (int i = 0; i < 30; ++i) for (int i = 0; i < 30; ++i) s += "%c";
s += "%c";
s += "}\n"; s += "}\n";
std::time_t t = std::time(FMT_NULL); std::time_t t = std::time(FMT_NULL);
fmt::format(s, *std::localtime(&t)); fmt::format(s, *std::localtime(&t));
@ -39,19 +38,13 @@ TEST(TimeTest, FormatToEmptyContainer) {
EXPECT_EQ(s, "42"); EXPECT_EQ(s, "42");
} }
TEST(TimeTest, EmptyResult) { TEST(TimeTest, EmptyResult) { EXPECT_EQ("", fmt::format("{}", std::tm())); }
EXPECT_EQ("", fmt::format("{}", std::tm()));
}
static bool EqualTime(const std::tm& lhs, const std::tm& rhs) { static bool EqualTime(const std::tm& lhs, const std::tm& rhs) {
return lhs.tm_sec == rhs.tm_sec && return lhs.tm_sec == rhs.tm_sec && lhs.tm_min == rhs.tm_min &&
lhs.tm_min == rhs.tm_min && lhs.tm_hour == rhs.tm_hour && lhs.tm_mday == rhs.tm_mday &&
lhs.tm_hour == rhs.tm_hour && lhs.tm_mon == rhs.tm_mon && lhs.tm_year == rhs.tm_year &&
lhs.tm_mday == rhs.tm_mday && lhs.tm_wday == rhs.tm_wday && lhs.tm_yday == rhs.tm_yday &&
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; lhs.tm_isdst == rhs.tm_isdst;
} }

View File

@ -38,7 +38,6 @@ fmt::buffered_file open_buffered_file(FILE **fp) {
write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT)); write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT));
write_end.close(); write_end.close();
fmt::buffered_file f = read_end.fdopen("r"); fmt::buffered_file f = read_end.fdopen("r");
if (fp) if (fp) *fp = f.get();
*fp = f.get();
return f; return f;
} }

View File

@ -48,8 +48,7 @@ inline FILE *safe_fopen(const char *filename, const char *mode) {
#endif #endif
} }
template <typename Char> template <typename Char> class BasicTestString {
class BasicTestString {
private: private:
std::basic_string<Char> value_; std::basic_string<Char> value_;
@ -61,21 +60,21 @@ class BasicTestString {
const std::basic_string<Char>& value() const { return value_; } const std::basic_string<Char>& value() const { return value_; }
}; };
template <typename Char> template <typename Char> const Char BasicTestString<Char>::EMPTY[] = {0};
const Char BasicTestString<Char>::EMPTY[] = {0};
typedef BasicTestString<char> TestString; typedef BasicTestString<char> TestString;
typedef BasicTestString<wchar_t> TestWString; typedef BasicTestString<wchar_t> TestWString;
template <typename Char> template <typename Char>
std::basic_ostream<Char> &operator<<( std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& os,
std::basic_ostream<Char> &os, const BasicTestString<Char> &s) { const BasicTestString<Char>& s) {
os << s.value(); os << s.value();
return os; return os;
} }
class Date { class Date {
int year_, month_, day_; int year_, month_, day_;
public: public:
Date(int year, int month, int day) : year_(year), month_(month), day_(day) {} Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}