Format the code using clang-format
This commit is contained in:
parent
9a777b9e1c
commit
58b6f8db48
8
.clang-format
Normal file
8
.clang-format
Normal 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
|
@ -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) throw format_error("invalid format");
|
||||||
if (ptr == end)
|
|
||||||
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,24 +205,23 @@ 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;
|
||||||
std::chrono::milliseconds ms;
|
std::chrono::milliseconds ms;
|
||||||
|
|
||||||
typedef typename FormatContext::char_type char_type;
|
typedef typename FormatContext::char_type char_type;
|
||||||
|
|
||||||
explicit chrono_formatter(FormatContext &ctx, OutputIt o)
|
explicit chrono_formatter(FormatContext& ctx, OutputIt o)
|
||||||
: context(ctx), out(o) {}
|
: context(ctx), out(o) {}
|
||||||
|
|
||||||
int hour() const { return to_int((s.count() / 3600) % 24); }
|
int hour() const { return to_int((s.count() / 3600) % 24); }
|
||||||
|
|
||||||
@ -251,14 +245,13 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void format_localized(const tm &time, const char *format) {
|
void format_localized(const tm& time, const char* format) {
|
||||||
auto locale = context.locale().template get<std::locale>();
|
auto locale = context.locale().template get<std::locale>();
|
||||||
auto &facet = std::use_facet<std::time_put<char_type>>(locale);
|
auto& facet = std::use_facet<std::time_put<char_type>>(locale);
|
||||||
std::basic_ostringstream<char_type> os;
|
std::basic_ostringstream<char_type> os;
|
||||||
os.imbue(locale);
|
os.imbue(locale);
|
||||||
facet.put(os, os, ' ', &time, format, format + std::strlen(format));
|
facet.put(os, os, ' ', &time, format, format + std::strlen(format));
|
||||||
@ -266,7 +259,7 @@ struct chrono_formatter {
|
|||||||
std::copy(str.begin(), str.end(), out);
|
std::copy(str.begin(), str.end(), out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_text(const char_type *begin, const char_type *end) {
|
void on_text(const char_type* begin, const char_type* end) {
|
||||||
std::copy(begin, end, out);
|
std::copy(begin, end, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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");
|
||||||
@ -341,30 +331,30 @@ struct chrono_formatter {
|
|||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
template <typename Period> FMT_CONSTEXPR const char *get_units() {
|
template <typename Period> FMT_CONSTEXPR const char* get_units() {
|
||||||
return FMT_NULL;
|
return FMT_NULL;
|
||||||
}
|
}
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::atto>() { return "as"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::atto>() { return "as"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::femto>() { return "fs"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::femto>() { return "fs"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::pico>() { return "ps"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::pico>() { return "ps"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::nano>() { return "ns"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::nano>() { return "ns"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::micro>() { return "µs"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::micro>() { return "µs"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::milli>() { return "ms"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::milli>() { return "ms"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::centi>() { return "cs"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::centi>() { return "cs"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::deci>() { return "ds"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::deci>() { return "ds"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::ratio<1>>() { return "s"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::ratio<1>>() { return "s"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::deca>() { return "das"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::deca>() { return "das"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::hecto>() { return "hs"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::hecto>() { return "hs"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::kilo>() { return "ks"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::kilo>() { return "ks"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::mega>() { return "Ms"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::mega>() { return "Ms"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::giga>() { return "Gs"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::giga>() { return "Gs"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::tera>() { return "Ts"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::tera>() { return "Ts"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::peta>() { return "Ps"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::peta>() { return "Ps"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::exa>() { return "Es"; }
|
template <> FMT_CONSTEXPR const char* get_units<std::exa>() { return "Es"; }
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::ratio<60>>() {
|
template <> FMT_CONSTEXPR const char* get_units<std::ratio<60>>() {
|
||||||
return "m";
|
return "m";
|
||||||
}
|
}
|
||||||
template <> FMT_CONSTEXPR const char *get_units<std::ratio<3600>>() {
|
template <> FMT_CONSTEXPR const char* get_units<std::ratio<3600>>() {
|
||||||
return "h";
|
return "h";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,12 +368,11 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
typedef std::chrono::duration<Rep, Period> duration;
|
typedef std::chrono::duration<Rep, Period> duration;
|
||||||
|
|
||||||
struct spec_handler {
|
struct spec_handler {
|
||||||
formatter &f;
|
formatter& f;
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -398,13 +387,12 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
return arg_ref_type(context.next_arg_id());
|
return arg_ref_type(context.next_arg_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_error(const char *msg) { throw format_error(msg); }
|
void on_error(const char* msg) { throw format_error(msg); }
|
||||||
void on_fill(Char fill) { f.spec.fill_ = fill; }
|
void on_fill(Char fill) { f.spec.fill_ = fill; }
|
||||||
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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -412,7 +400,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
public:
|
public:
|
||||||
formatter() : spec() {}
|
formatter() : spec() {}
|
||||||
|
|
||||||
FMT_CONSTEXPR auto parse(basic_parse_context<Char> &ctx)
|
FMT_CONSTEXPR auto parse(basic_parse_context<Char>& ctx)
|
||||||
-> decltype(ctx.begin()) {
|
-> decltype(ctx.begin()) {
|
||||||
auto begin = ctx.begin(), end = ctx.end();
|
auto begin = ctx.begin(), end = ctx.end();
|
||||||
if (begin == end) return begin;
|
if (begin == end) return begin;
|
||||||
@ -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.
|
||||||
@ -436,7 +423,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
typedef output_range<decltype(ctx.out()), Char> range;
|
typedef output_range<decltype(ctx.out()), Char> range;
|
||||||
basic_writer<range> w(range(ctx.out()));
|
basic_writer<range> w(range(ctx.out()));
|
||||||
if (begin == end || *begin == '}') {
|
if (begin == end || *begin == '}') {
|
||||||
if (const char *unit = get_units<Period>())
|
if (const char* unit = get_units<Period>())
|
||||||
format_to(buf, "{}{}", d.count(), unit);
|
format_to(buf, "{}{}", d.count(), unit);
|
||||||
else if (Period::den == 1)
|
else if (Period::den == 1)
|
||||||
format_to(buf, "{}[{}]s", d.count(), Period::num);
|
format_to(buf, "{}[{}]s", d.count(), Period::num);
|
||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -20,12 +20,12 @@ FMT_API void vprint_colored(color c, string_view format, format_args args);
|
|||||||
FMT_API void vprint_colored(color c, wstring_view format, wformat_args args);
|
FMT_API void vprint_colored(color c, wstring_view format, wformat_args args);
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline void print_colored(color c, string_view format_str,
|
inline void print_colored(color c, string_view format_str,
|
||||||
const Args & ... args) {
|
const Args&... args) {
|
||||||
vprint_colored(c, format_str, make_format_args(args...));
|
vprint_colored(c, format_str, make_format_args(args...));
|
||||||
}
|
}
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline void print_colored(color c, wstring_view format_str,
|
inline void print_colored(color c, wstring_view format_str,
|
||||||
const Args & ... args) {
|
const Args&... args) {
|
||||||
vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
|
vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,148 +48,148 @@ inline void vprint_colored(color c, wstring_view format, wformat_args args) {
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
enum class color : uint32_t {
|
enum class color : uint32_t {
|
||||||
alice_blue = 0xF0F8FF, // rgb(240,248,255)
|
alice_blue = 0xF0F8FF, // rgb(240,248,255)
|
||||||
antique_white = 0xFAEBD7, // rgb(250,235,215)
|
antique_white = 0xFAEBD7, // rgb(250,235,215)
|
||||||
aqua = 0x00FFFF, // rgb(0,255,255)
|
aqua = 0x00FFFF, // rgb(0,255,255)
|
||||||
aquamarine = 0x7FFFD4, // rgb(127,255,212)
|
aquamarine = 0x7FFFD4, // rgb(127,255,212)
|
||||||
azure = 0xF0FFFF, // rgb(240,255,255)
|
azure = 0xF0FFFF, // rgb(240,255,255)
|
||||||
beige = 0xF5F5DC, // rgb(245,245,220)
|
beige = 0xF5F5DC, // rgb(245,245,220)
|
||||||
bisque = 0xFFE4C4, // rgb(255,228,196)
|
bisque = 0xFFE4C4, // rgb(255,228,196)
|
||||||
black = 0x000000, // rgb(0,0,0)
|
black = 0x000000, // rgb(0,0,0)
|
||||||
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
|
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
|
||||||
blue = 0x0000FF, // rgb(0,0,255)
|
blue = 0x0000FF, // rgb(0,0,255)
|
||||||
blue_violet = 0x8A2BE2, // rgb(138,43,226)
|
blue_violet = 0x8A2BE2, // rgb(138,43,226)
|
||||||
brown = 0xA52A2A, // rgb(165,42,42)
|
brown = 0xA52A2A, // rgb(165,42,42)
|
||||||
burly_wood = 0xDEB887, // rgb(222,184,135)
|
burly_wood = 0xDEB887, // rgb(222,184,135)
|
||||||
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
|
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
|
||||||
chartreuse = 0x7FFF00, // rgb(127,255,0)
|
chartreuse = 0x7FFF00, // rgb(127,255,0)
|
||||||
chocolate = 0xD2691E, // rgb(210,105,30)
|
chocolate = 0xD2691E, // rgb(210,105,30)
|
||||||
coral = 0xFF7F50, // rgb(255,127,80)
|
coral = 0xFF7F50, // rgb(255,127,80)
|
||||||
cornflower_blue = 0x6495ED, // rgb(100,149,237)
|
cornflower_blue = 0x6495ED, // rgb(100,149,237)
|
||||||
cornsilk = 0xFFF8DC, // rgb(255,248,220)
|
cornsilk = 0xFFF8DC, // rgb(255,248,220)
|
||||||
crimson = 0xDC143C, // rgb(220,20,60)
|
crimson = 0xDC143C, // rgb(220,20,60)
|
||||||
cyan = 0x00FFFF, // rgb(0,255,255)
|
cyan = 0x00FFFF, // rgb(0,255,255)
|
||||||
dark_blue = 0x00008B, // rgb(0,0,139)
|
dark_blue = 0x00008B, // rgb(0,0,139)
|
||||||
dark_cyan = 0x008B8B, // rgb(0,139,139)
|
dark_cyan = 0x008B8B, // rgb(0,139,139)
|
||||||
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
|
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
|
||||||
dark_gray = 0xA9A9A9, // rgb(169,169,169)
|
dark_gray = 0xA9A9A9, // rgb(169,169,169)
|
||||||
dark_green = 0x006400, // rgb(0,100,0)
|
dark_green = 0x006400, // rgb(0,100,0)
|
||||||
dark_khaki = 0xBDB76B, // rgb(189,183,107)
|
dark_khaki = 0xBDB76B, // rgb(189,183,107)
|
||||||
dark_magenta = 0x8B008B, // rgb(139,0,139)
|
dark_magenta = 0x8B008B, // rgb(139,0,139)
|
||||||
dark_olive_green = 0x556B2F, // rgb(85,107,47)
|
dark_olive_green = 0x556B2F, // rgb(85,107,47)
|
||||||
dark_orange = 0xFF8C00, // rgb(255,140,0)
|
dark_orange = 0xFF8C00, // rgb(255,140,0)
|
||||||
dark_orchid = 0x9932CC, // rgb(153,50,204)
|
dark_orchid = 0x9932CC, // rgb(153,50,204)
|
||||||
dark_red = 0x8B0000, // rgb(139,0,0)
|
dark_red = 0x8B0000, // rgb(139,0,0)
|
||||||
dark_salmon = 0xE9967A, // rgb(233,150,122)
|
dark_salmon = 0xE9967A, // rgb(233,150,122)
|
||||||
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
|
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
|
||||||
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
|
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
|
||||||
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
|
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
|
||||||
dark_turquoise = 0x00CED1, // rgb(0,206,209)
|
dark_turquoise = 0x00CED1, // rgb(0,206,209)
|
||||||
dark_violet = 0x9400D3, // rgb(148,0,211)
|
dark_violet = 0x9400D3, // rgb(148,0,211)
|
||||||
deep_pink = 0xFF1493, // rgb(255,20,147)
|
deep_pink = 0xFF1493, // rgb(255,20,147)
|
||||||
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
|
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
|
||||||
dim_gray = 0x696969, // rgb(105,105,105)
|
dim_gray = 0x696969, // rgb(105,105,105)
|
||||||
dodger_blue = 0x1E90FF, // rgb(30,144,255)
|
dodger_blue = 0x1E90FF, // rgb(30,144,255)
|
||||||
fire_brick = 0xB22222, // rgb(178,34,34)
|
fire_brick = 0xB22222, // rgb(178,34,34)
|
||||||
floral_white = 0xFFFAF0, // rgb(255,250,240)
|
floral_white = 0xFFFAF0, // rgb(255,250,240)
|
||||||
forest_green = 0x228B22, // rgb(34,139,34)
|
forest_green = 0x228B22, // rgb(34,139,34)
|
||||||
fuchsia = 0xFF00FF, // rgb(255,0,255)
|
fuchsia = 0xFF00FF, // rgb(255,0,255)
|
||||||
gainsboro = 0xDCDCDC, // rgb(220,220,220)
|
gainsboro = 0xDCDCDC, // rgb(220,220,220)
|
||||||
ghost_white = 0xF8F8FF, // rgb(248,248,255)
|
ghost_white = 0xF8F8FF, // rgb(248,248,255)
|
||||||
gold = 0xFFD700, // rgb(255,215,0)
|
gold = 0xFFD700, // rgb(255,215,0)
|
||||||
golden_rod = 0xDAA520, // rgb(218,165,32)
|
golden_rod = 0xDAA520, // rgb(218,165,32)
|
||||||
gray = 0x808080, // rgb(128,128,128)
|
gray = 0x808080, // rgb(128,128,128)
|
||||||
green = 0x008000, // rgb(0,128,0)
|
green = 0x008000, // rgb(0,128,0)
|
||||||
green_yellow = 0xADFF2F, // rgb(173,255,47)
|
green_yellow = 0xADFF2F, // rgb(173,255,47)
|
||||||
honey_dew = 0xF0FFF0, // rgb(240,255,240)
|
honey_dew = 0xF0FFF0, // rgb(240,255,240)
|
||||||
hot_pink = 0xFF69B4, // rgb(255,105,180)
|
hot_pink = 0xFF69B4, // rgb(255,105,180)
|
||||||
indian_red = 0xCD5C5C, // rgb(205,92,92)
|
indian_red = 0xCD5C5C, // rgb(205,92,92)
|
||||||
indigo = 0x4B0082, // rgb(75,0,130)
|
indigo = 0x4B0082, // rgb(75,0,130)
|
||||||
ivory = 0xFFFFF0, // rgb(255,255,240)
|
ivory = 0xFFFFF0, // rgb(255,255,240)
|
||||||
khaki = 0xF0E68C, // rgb(240,230,140)
|
khaki = 0xF0E68C, // rgb(240,230,140)
|
||||||
lavender = 0xE6E6FA, // rgb(230,230,250)
|
lavender = 0xE6E6FA, // rgb(230,230,250)
|
||||||
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
|
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
|
||||||
lawn_green = 0x7CFC00, // rgb(124,252,0)
|
lawn_green = 0x7CFC00, // rgb(124,252,0)
|
||||||
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
|
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
|
||||||
light_blue = 0xADD8E6, // rgb(173,216,230)
|
light_blue = 0xADD8E6, // rgb(173,216,230)
|
||||||
light_coral = 0xF08080, // rgb(240,128,128)
|
light_coral = 0xF08080, // rgb(240,128,128)
|
||||||
light_cyan = 0xE0FFFF, // rgb(224,255,255)
|
light_cyan = 0xE0FFFF, // rgb(224,255,255)
|
||||||
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
|
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
|
||||||
light_gray = 0xD3D3D3, // rgb(211,211,211)
|
light_gray = 0xD3D3D3, // rgb(211,211,211)
|
||||||
light_green = 0x90EE90, // rgb(144,238,144)
|
light_green = 0x90EE90, // rgb(144,238,144)
|
||||||
light_pink = 0xFFB6C1, // rgb(255,182,193)
|
light_pink = 0xFFB6C1, // rgb(255,182,193)
|
||||||
light_salmon = 0xFFA07A, // rgb(255,160,122)
|
light_salmon = 0xFFA07A, // rgb(255,160,122)
|
||||||
light_sea_green = 0x20B2AA, // rgb(32,178,170)
|
light_sea_green = 0x20B2AA, // rgb(32,178,170)
|
||||||
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
|
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
|
||||||
light_slate_gray = 0x778899, // rgb(119,136,153)
|
light_slate_gray = 0x778899, // rgb(119,136,153)
|
||||||
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
|
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
|
||||||
light_yellow = 0xFFFFE0, // rgb(255,255,224)
|
light_yellow = 0xFFFFE0, // rgb(255,255,224)
|
||||||
lime = 0x00FF00, // rgb(0,255,0)
|
lime = 0x00FF00, // rgb(0,255,0)
|
||||||
lime_green = 0x32CD32, // rgb(50,205,50)
|
lime_green = 0x32CD32, // rgb(50,205,50)
|
||||||
linen = 0xFAF0E6, // rgb(250,240,230)
|
linen = 0xFAF0E6, // rgb(250,240,230)
|
||||||
magenta = 0xFF00FF, // rgb(255,0,255)
|
magenta = 0xFF00FF, // rgb(255,0,255)
|
||||||
maroon = 0x800000, // rgb(128,0,0)
|
maroon = 0x800000, // rgb(128,0,0)
|
||||||
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
|
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
|
||||||
medium_blue = 0x0000CD, // rgb(0,0,205)
|
medium_blue = 0x0000CD, // rgb(0,0,205)
|
||||||
medium_orchid = 0xBA55D3, // rgb(186,85,211)
|
medium_orchid = 0xBA55D3, // rgb(186,85,211)
|
||||||
medium_purple = 0x9370DB, // rgb(147,112,219)
|
medium_purple = 0x9370DB, // rgb(147,112,219)
|
||||||
medium_sea_green = 0x3CB371, // rgb(60,179,113)
|
medium_sea_green = 0x3CB371, // rgb(60,179,113)
|
||||||
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
|
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
|
||||||
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
|
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
|
||||||
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
|
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
|
||||||
medium_violet_red = 0xC71585, // rgb(199,21,133)
|
medium_violet_red = 0xC71585, // rgb(199,21,133)
|
||||||
midnight_blue = 0x191970, // rgb(25,25,112)
|
midnight_blue = 0x191970, // rgb(25,25,112)
|
||||||
mint_cream = 0xF5FFFA, // rgb(245,255,250)
|
mint_cream = 0xF5FFFA, // rgb(245,255,250)
|
||||||
misty_rose = 0xFFE4E1, // rgb(255,228,225)
|
misty_rose = 0xFFE4E1, // rgb(255,228,225)
|
||||||
moccasin = 0xFFE4B5, // rgb(255,228,181)
|
moccasin = 0xFFE4B5, // rgb(255,228,181)
|
||||||
navajo_white = 0xFFDEAD, // rgb(255,222,173)
|
navajo_white = 0xFFDEAD, // rgb(255,222,173)
|
||||||
navy = 0x000080, // rgb(0,0,128)
|
navy = 0x000080, // rgb(0,0,128)
|
||||||
old_lace = 0xFDF5E6, // rgb(253,245,230)
|
old_lace = 0xFDF5E6, // rgb(253,245,230)
|
||||||
olive = 0x808000, // rgb(128,128,0)
|
olive = 0x808000, // rgb(128,128,0)
|
||||||
olive_drab = 0x6B8E23, // rgb(107,142,35)
|
olive_drab = 0x6B8E23, // rgb(107,142,35)
|
||||||
orange = 0xFFA500, // rgb(255,165,0)
|
orange = 0xFFA500, // rgb(255,165,0)
|
||||||
orange_red = 0xFF4500, // rgb(255,69,0)
|
orange_red = 0xFF4500, // rgb(255,69,0)
|
||||||
orchid = 0xDA70D6, // rgb(218,112,214)
|
orchid = 0xDA70D6, // rgb(218,112,214)
|
||||||
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
|
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
|
||||||
pale_green = 0x98FB98, // rgb(152,251,152)
|
pale_green = 0x98FB98, // rgb(152,251,152)
|
||||||
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
|
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
|
||||||
pale_violet_red = 0xDB7093, // rgb(219,112,147)
|
pale_violet_red = 0xDB7093, // rgb(219,112,147)
|
||||||
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
|
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
|
||||||
peach_puff = 0xFFDAB9, // rgb(255,218,185)
|
peach_puff = 0xFFDAB9, // rgb(255,218,185)
|
||||||
peru = 0xCD853F, // rgb(205,133,63)
|
peru = 0xCD853F, // rgb(205,133,63)
|
||||||
pink = 0xFFC0CB, // rgb(255,192,203)
|
pink = 0xFFC0CB, // rgb(255,192,203)
|
||||||
plum = 0xDDA0DD, // rgb(221,160,221)
|
plum = 0xDDA0DD, // rgb(221,160,221)
|
||||||
powder_blue = 0xB0E0E6, // rgb(176,224,230)
|
powder_blue = 0xB0E0E6, // rgb(176,224,230)
|
||||||
purple = 0x800080, // rgb(128,0,128)
|
purple = 0x800080, // rgb(128,0,128)
|
||||||
rebecca_purple = 0x663399, // rgb(102,51,153)
|
rebecca_purple = 0x663399, // rgb(102,51,153)
|
||||||
red = 0xFF0000, // rgb(255,0,0)
|
red = 0xFF0000, // rgb(255,0,0)
|
||||||
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
|
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
|
||||||
royal_blue = 0x4169E1, // rgb(65,105,225)
|
royal_blue = 0x4169E1, // rgb(65,105,225)
|
||||||
saddle_brown = 0x8B4513, // rgb(139,69,19)
|
saddle_brown = 0x8B4513, // rgb(139,69,19)
|
||||||
salmon = 0xFA8072, // rgb(250,128,114)
|
salmon = 0xFA8072, // rgb(250,128,114)
|
||||||
sandy_brown = 0xF4A460, // rgb(244,164,96)
|
sandy_brown = 0xF4A460, // rgb(244,164,96)
|
||||||
sea_green = 0x2E8B57, // rgb(46,139,87)
|
sea_green = 0x2E8B57, // rgb(46,139,87)
|
||||||
sea_shell = 0xFFF5EE, // rgb(255,245,238)
|
sea_shell = 0xFFF5EE, // rgb(255,245,238)
|
||||||
sienna = 0xA0522D, // rgb(160,82,45)
|
sienna = 0xA0522D, // rgb(160,82,45)
|
||||||
silver = 0xC0C0C0, // rgb(192,192,192)
|
silver = 0xC0C0C0, // rgb(192,192,192)
|
||||||
sky_blue = 0x87CEEB, // rgb(135,206,235)
|
sky_blue = 0x87CEEB, // rgb(135,206,235)
|
||||||
slate_blue = 0x6A5ACD, // rgb(106,90,205)
|
slate_blue = 0x6A5ACD, // rgb(106,90,205)
|
||||||
slate_gray = 0x708090, // rgb(112,128,144)
|
slate_gray = 0x708090, // rgb(112,128,144)
|
||||||
snow = 0xFFFAFA, // rgb(255,250,250)
|
snow = 0xFFFAFA, // rgb(255,250,250)
|
||||||
spring_green = 0x00FF7F, // rgb(0,255,127)
|
spring_green = 0x00FF7F, // rgb(0,255,127)
|
||||||
steel_blue = 0x4682B4, // rgb(70,130,180)
|
steel_blue = 0x4682B4, // rgb(70,130,180)
|
||||||
tan = 0xD2B48C, // rgb(210,180,140)
|
tan = 0xD2B48C, // rgb(210,180,140)
|
||||||
teal = 0x008080, // rgb(0,128,128)
|
teal = 0x008080, // rgb(0,128,128)
|
||||||
thistle = 0xD8BFD8, // rgb(216,191,216)
|
thistle = 0xD8BFD8, // rgb(216,191,216)
|
||||||
tomato = 0xFF6347, // rgb(255,99,71)
|
tomato = 0xFF6347, // rgb(255,99,71)
|
||||||
turquoise = 0x40E0D0, // rgb(64,224,208)
|
turquoise = 0x40E0D0, // rgb(64,224,208)
|
||||||
violet = 0xEE82EE, // rgb(238,130,238)
|
violet = 0xEE82EE, // rgb(238,130,238)
|
||||||
wheat = 0xF5DEB3, // rgb(245,222,179)
|
wheat = 0xF5DEB3, // rgb(245,222,179)
|
||||||
white = 0xFFFFFF, // rgb(255,255,255)
|
white = 0xFFFFFF, // rgb(255,255,255)
|
||||||
white_smoke = 0xF5F5F5, // rgb(245,245,245)
|
white_smoke = 0xF5F5F5, // rgb(245,245,245)
|
||||||
yellow = 0xFFFF00, // rgb(255,255,0)
|
yellow = 0xFFFF00, // rgb(255,255,0)
|
||||||
yellow_green = 0x9ACD32 // rgb(154,205,50)
|
yellow_green = 0x9ACD32 // rgb(154,205,50)
|
||||||
}; // enum class color
|
}; // enum class color
|
||||||
|
|
||||||
enum class terminal_color : uint8_t {
|
enum class terminal_color : uint8_t {
|
||||||
black = 30,
|
black = 30,
|
||||||
@ -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;
|
||||||
@ -258,15 +257,17 @@ struct color_type {
|
|||||||
uint32_t rgb_color;
|
uint32_t rgb_color;
|
||||||
} value;
|
} value;
|
||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
// Experimental text formatting support.
|
// Experimental text formatting support.
|
||||||
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) {
|
||||||
set_foreground_color = rhs.set_foreground_color;
|
set_foreground_color = rhs.set_foreground_color;
|
||||||
foreground_color = rhs.foreground_color;
|
foreground_color = rhs.foreground_color;
|
||||||
@ -290,12 +291,12 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
set_foreground_color = rhs.set_foreground_color;
|
set_foreground_color = rhs.set_foreground_color;
|
||||||
foreground_color = rhs.foreground_color;
|
foreground_color = rhs.foreground_color;
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,20 +347,20 @@ class text_style {
|
|||||||
return ems;
|
return ems;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FMT_CONSTEXPR text_style(bool is_foreground,
|
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||||
internal::color_type text_color) FMT_NOEXCEPT
|
internal::color_type text_color) FMT_NOEXCEPT
|
||||||
: set_foreground_color(),
|
: set_foreground_color(),
|
||||||
set_background_color(),
|
set_background_color(),
|
||||||
ems() {
|
ems() {
|
||||||
if (is_foreground) {
|
if (is_foreground) {
|
||||||
foreground_color = text_color;
|
foreground_color = text_color;
|
||||||
set_foreground_color = true;
|
set_foreground_color = true;
|
||||||
} else {
|
} else {
|
||||||
background_color = text_color;
|
background_color = text_color;
|
||||||
set_background_color = true;
|
set_background_color = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)
|
friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)
|
||||||
FMT_NOEXCEPT;
|
FMT_NOEXCEPT;
|
||||||
@ -387,10 +388,9 @@ 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
|
||||||
// sequence.
|
// sequence.
|
||||||
if (!text_color.is_rgb) {
|
if (!text_color.is_rgb) {
|
||||||
@ -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');
|
||||||
@ -421,7 +420,7 @@ struct ansi_color_escape {
|
|||||||
buffer[i] = static_cast<Char>(esc[i]);
|
buffer[i] = static_cast<Char>(esc[i]);
|
||||||
}
|
}
|
||||||
rgb color(text_color.value.rgb_color);
|
rgb color(text_color.value.rgb_color);
|
||||||
to_esc(color.r, buffer + 7, ';');
|
to_esc(color.r, buffer + 7, ';');
|
||||||
to_esc(color.g, buffer + 11, ';');
|
to_esc(color.g, buffer + 11, ';');
|
||||||
to_esc(color.b, buffer + 15, 'm');
|
to_esc(color.b, buffer + 15, 'm');
|
||||||
buffer[19] = static_cast<Char>(0);
|
buffer[19] = static_cast<Char>(0);
|
||||||
@ -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]);
|
||||||
@ -449,19 +444,17 @@ struct ansi_color_escape {
|
|||||||
}
|
}
|
||||||
buffer[index++] = static_cast<Char>(0);
|
buffer[index++] = static_cast<Char>(0);
|
||||||
}
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Char buffer[7u + 3u * 4u + 1u];
|
Char buffer[7u + 3u * 4u + 1u];
|
||||||
|
|
||||||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out,
|
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
||||||
char delimiter) FMT_NOEXCEPT {
|
char delimiter) FMT_NOEXCEPT {
|
||||||
out[0] = static_cast<Char>('0' + c / 100);
|
out[0] = static_cast<Char>('0' + c / 100);
|
||||||
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||||
@ -471,40 +464,37 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
inline void fputs(const Char *chars, FILE *stream) FMT_NOEXCEPT {
|
inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT {
|
||||||
std::fputs(chars, stream);
|
std::fputs(chars, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline void fputs<wchar_t>(const wchar_t *chars, FILE *stream) FMT_NOEXCEPT {
|
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,27 +509,24 @@ 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(
|
||||||
const text_style &ts, basic_string_view<Char> format_str,
|
const text_style& ts, 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;
|
||||||
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()) {
|
||||||
has_style = true;
|
has_style = true;
|
||||||
ansi_color_escape<Char> escape =
|
ansi_color_escape<Char> escape =
|
||||||
make_foreground_color<Char>(ts.get_foreground());
|
make_foreground_color<Char>(ts.get_foreground());
|
||||||
buffer.append(escape.begin(), escape.end());
|
buffer.append(escape.begin(), escape.end());
|
||||||
}
|
}
|
||||||
if (ts.has_background()) {
|
if (ts.has_background()) {
|
||||||
@ -554,22 +541,20 @@ std::basic_string<Char> vformat(
|
|||||||
}
|
}
|
||||||
return fmt::to_string(buffer);
|
return fmt::to_string(buffer);
|
||||||
}
|
}
|
||||||
} // 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;
|
||||||
internal::fputs<Char>(
|
internal::fputs<Char>(
|
||||||
internal::make_foreground_color<Char>(ts.get_foreground()), f);
|
internal::make_foreground_color<Char>(ts.get_foreground()), f);
|
||||||
}
|
}
|
||||||
if (ts.has_background()) {
|
if (ts.has_background()) {
|
||||||
has_style = true;
|
has_style = true;
|
||||||
@ -591,8 +576,8 @@ void vprint(std::FILE *f, const text_style &ts, const S &format,
|
|||||||
*/
|
*/
|
||||||
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(
|
||||||
std::FILE *f, const text_style &ts, const String &format_str,
|
std::FILE* f, const text_style& ts, const String& format_str,
|
||||||
const Args &... args) {
|
const Args&... args) {
|
||||||
internal::check_format_string<Args...>(format_str);
|
internal::check_format_string<Args...>(format_str);
|
||||||
typedef typename internal::char_t<String>::type char_t;
|
typedef typename internal::char_t<String>::type char_t;
|
||||||
typedef typename buffer_context<char_t>::type context_t;
|
typedef typename buffer_context<char_t>::type context_t;
|
||||||
@ -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,11 +618,12 @@ 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...));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -20,45 +20,45 @@
|
|||||||
#include <cstddef> // for std::ptrdiff_t
|
#include <cstddef> // for std::ptrdiff_t
|
||||||
#include <cstring> // for std::memmove
|
#include <cstring> // for std::memmove
|
||||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||||
# include <locale>
|
# include <locale>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FMT_USE_WINDOWS_H
|
#if FMT_USE_WINDOWS_H
|
||||||
# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
|
# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
|
||||||
# define WIN32_LEAN_AND_MEAN
|
# define WIN32_LEAN_AND_MEAN
|
||||||
# endif
|
# endif
|
||||||
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
|
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
# else
|
# else
|
||||||
# define NOMINMAX
|
# define NOMINMAX
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
# undef NOMINMAX
|
# undef NOMINMAX
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FMT_EXCEPTIONS
|
#if FMT_EXCEPTIONS
|
||||||
# define FMT_TRY try
|
# define FMT_TRY try
|
||||||
# define FMT_CATCH(x) catch (x)
|
# define FMT_CATCH(x) catch (x)
|
||||||
#else
|
#else
|
||||||
# define FMT_TRY if (true)
|
# define FMT_TRY if (true)
|
||||||
# define FMT_CATCH(x) if (false)
|
# define FMT_CATCH(x) if (false)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# pragma warning(push)
|
# pragma warning(push)
|
||||||
# pragma warning(disable: 4127) // conditional expression is constant
|
# pragma warning(disable : 4127) // conditional expression is constant
|
||||||
# pragma warning(disable: 4702) // unreachable code
|
# pragma warning(disable : 4702) // unreachable code
|
||||||
// Disable deprecation warning for strerror. The latter is not called but
|
// Disable deprecation warning for strerror. The latter is not called but
|
||||||
// MSVC fails to detect it.
|
// MSVC fails to detect it.
|
||||||
# pragma warning(disable: 4996)
|
# pragma warning(disable : 4996)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Dummy implementations of strerror_r and strerror_s called if corresponding
|
// Dummy implementations of strerror_r and strerror_s called if corresponding
|
||||||
// system functions are not available.
|
// system functions are not available.
|
||||||
inline fmt::internal::null<> strerror_r(int, char *, ...) {
|
inline fmt::internal::null<> strerror_r(int, char*, ...) {
|
||||||
return fmt::internal::null<>();
|
return fmt::internal::null<>();
|
||||||
}
|
}
|
||||||
inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) {
|
inline fmt::internal::null<> strerror_s(char*, std::size_t, ...) {
|
||||||
return fmt::internal::null<>();
|
return fmt::internal::null<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,25 +67,25 @@ FMT_BEGIN_NAMESPACE
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
# define FMT_SNPRINTF snprintf
|
# define FMT_SNPRINTF snprintf
|
||||||
#else // _MSC_VER
|
#else // _MSC_VER
|
||||||
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
|
inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
|
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
# define FMT_SNPRINTF fmt_snprintf
|
# define FMT_SNPRINTF fmt_snprintf
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
|
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
|
||||||
# define FMT_SWPRINTF snwprintf
|
# define FMT_SWPRINTF snwprintf
|
||||||
#else
|
#else
|
||||||
# define FMT_SWPRINTF swprintf
|
# define FMT_SWPRINTF swprintf
|
||||||
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
|
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
|
||||||
|
|
||||||
typedef void (*FormatFunc)(internal::buffer &, int, string_view);
|
typedef void (*FormatFunc)(internal::buffer&, int, string_view);
|
||||||
|
|
||||||
// Portable thread-safe version of strerror.
|
// Portable thread-safe version of strerror.
|
||||||
// Sets buffer to point to a string describing the error code.
|
// Sets buffer to point to a string describing the error code.
|
||||||
@ -96,18 +96,18 @@ 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 {
|
||||||
private:
|
private:
|
||||||
int error_code_;
|
int error_code_;
|
||||||
char *&buffer_;
|
char*& buffer_;
|
||||||
std::size_t buffer_size_;
|
std::size_t buffer_size_;
|
||||||
|
|
||||||
// A noop assignment operator to avoid bogus warnings.
|
// A noop assignment operator to avoid bogus warnings.
|
||||||
void operator=(const dispatcher &) {}
|
void operator=(const dispatcher&) {}
|
||||||
|
|
||||||
// Handle the result of XSI-compliant version of strerror_r.
|
// Handle the result of XSI-compliant version of strerror_r.
|
||||||
int handle(int result) {
|
int handle(int result) {
|
||||||
@ -116,7 +116,7 @@ int safe_strerror(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle the result of GNU-specific version of strerror_r.
|
// Handle the result of GNU-specific version of strerror_r.
|
||||||
int handle(char *message) {
|
int handle(char* message) {
|
||||||
// If the buffer is full then the message is probably truncated.
|
// If the buffer is full then the message is probably truncated.
|
||||||
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
|
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
|
||||||
return ERANGE;
|
return ERANGE;
|
||||||
@ -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
|
||||||
@ -146,17 +146,15 @@ int safe_strerror(
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
void format_error_code(internal::buffer &out, int error_code,
|
void format_error_code(internal::buffer& out, int error_code,
|
||||||
string_view message) FMT_NOEXCEPT {
|
string_view message) FMT_NOEXCEPT {
|
||||||
// Report error code making sure that the output fits into
|
// Report error code making sure that the output fits into
|
||||||
// inline_buffer_size to avoid dynamic memory allocation and potential
|
// inline_buffer_size to avoid dynamic memory allocation and potential
|
||||||
@ -195,11 +193,10 @@ void report_error(FormatFunc func, int error_code,
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
|
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;
|
||||||
}
|
}
|
||||||
@ -208,22 +205,20 @@ FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
|
|||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template <typename Locale>
|
template <typename Locale>
|
||||||
locale_ref::locale_ref(const Locale &loc) : locale_(&loc) {
|
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,31 +226,30 @@ 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));
|
||||||
std::runtime_error &base = *this;
|
std::runtime_error& base = *this;
|
||||||
base = std::runtime_error(to_string(buffer));
|
base = std::runtime_error(to_string(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
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>
|
||||||
@ -266,86 +260,75 @@ const char basic_data<T>::DIGITS[] =
|
|||||||
"6061626364656667686970717273747576777879"
|
"6061626364656667686970717273747576777879"
|
||||||
"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 * 1000000000
|
||||||
factor * 10000, \
|
|
||||||
factor * 100000, \
|
|
||||||
factor * 1000000, \
|
|
||||||
factor * 10000000, \
|
|
||||||
factor * 100000000, \
|
|
||||||
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.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
|
const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
|
||||||
0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76,
|
0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76,
|
||||||
0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df,
|
0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df,
|
||||||
0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c,
|
0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c,
|
||||||
0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
|
0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
|
||||||
0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57,
|
0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57,
|
||||||
0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7,
|
0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7,
|
||||||
0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e,
|
0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e,
|
||||||
0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
|
0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
|
||||||
0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126,
|
0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126,
|
||||||
0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053,
|
0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053,
|
||||||
0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f,
|
0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f,
|
||||||
0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
|
0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
|
||||||
0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06,
|
0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06,
|
||||||
0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb,
|
0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb,
|
||||||
0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000,
|
0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000,
|
||||||
0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
|
0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
|
||||||
0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068,
|
0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068,
|
||||||
0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8,
|
0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8,
|
||||||
0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758,
|
0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758,
|
||||||
0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
|
0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
|
||||||
0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d,
|
0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d,
|
||||||
0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25,
|
0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25,
|
||||||
0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2,
|
0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2,
|
||||||
0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
|
0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
|
||||||
0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410,
|
0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410,
|
||||||
0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129,
|
0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129,
|
||||||
0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85,
|
0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85,
|
||||||
0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
|
0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
|
||||||
0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b,
|
0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
|
// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
|
||||||
// to significands above.
|
// to significands above.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const int16_t basic_data<T>::POW10_EXPONENTS[] = {
|
const int16_t basic_data<T>::POW10_EXPONENTS[] = {
|
||||||
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954,
|
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954,
|
||||||
-927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661,
|
-927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661,
|
||||||
-635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369,
|
-635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369,
|
||||||
-343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77,
|
-343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77,
|
||||||
-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";
|
||||||
|
|
||||||
@ -356,33 +339,32 @@ class fp {
|
|||||||
|
|
||||||
// All sizes are in bits.
|
// All sizes are in bits.
|
||||||
static FMT_CONSTEXPR_DECL const int char_size =
|
static FMT_CONSTEXPR_DECL const int char_size =
|
||||||
std::numeric_limits<unsigned char>::digits;
|
std::numeric_limits<unsigned char>::digits;
|
||||||
// Subtract 1 to account for an implicit most significant bit in the
|
// Subtract 1 to account for an implicit most significant bit in the
|
||||||
// normalized form.
|
// normalized form.
|
||||||
static FMT_CONSTEXPR_DECL const int double_significand_size =
|
static FMT_CONSTEXPR_DECL const int double_significand_size =
|
||||||
std::numeric_limits<double>::digits - 1;
|
std::numeric_limits<double>::digits - 1;
|
||||||
static FMT_CONSTEXPR_DECL const uint64_t implicit_bit =
|
static FMT_CONSTEXPR_DECL const uint64_t implicit_bit =
|
||||||
1ull << double_significand_size;
|
1ull << double_significand_size;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
significand_type f;
|
significand_type f;
|
||||||
int e;
|
int e;
|
||||||
|
|
||||||
static FMT_CONSTEXPR_DECL const int significand_size =
|
static FMT_CONSTEXPR_DECL const int significand_size =
|
||||||
sizeof(significand_type) * char_size;
|
sizeof(significand_type) * char_size;
|
||||||
|
|
||||||
fp(): f(0), e(0) {}
|
fp() : f(0), e(0) {}
|
||||||
fp(uint64_t f_val, int e_val): f(f_val), e(e_val) {}
|
fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {}
|
||||||
|
|
||||||
// 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);
|
||||||
const int exponent_size =
|
const int exponent_size =
|
||||||
double_size - double_significand_size - 1; // -1 for sign
|
double_size - double_significand_size - 1; // -1 for sign
|
||||||
const uint64_t significand_mask = implicit_bit - 1;
|
const uint64_t significand_mask = implicit_bit - 1;
|
||||||
const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;
|
const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;
|
||||||
const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
|
const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
|
||||||
@ -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) {
|
||||||
@ -415,9 +396,9 @@ class fp {
|
|||||||
// a boundary is a value half way between the number and its predecessor
|
// a boundary is a value half way between the number and its predecessor
|
||||||
// (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,12 +413,13 @@ 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
|
||||||
// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3.
|
// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3.
|
||||||
FMT_API fp get_cached_power(int min_exponent, int &pow10_exponent);
|
FMT_API fp get_cached_power(int min_exponent, int& pow10_exponent);
|
||||||
|
|
||||||
FMT_FUNC fp operator*(fp x, fp y) {
|
FMT_FUNC fp operator*(fp x, fp y) {
|
||||||
// Multiply 32-bit parts of significands.
|
// Multiply 32-bit parts of significands.
|
||||||
@ -450,10 +432,10 @@ FMT_FUNC fp operator*(fp x, fp y) {
|
|||||||
return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
|
return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
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,55 +445,84 @@ 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 + exp < diff || diff - remainder > remainder + exp - diff)) {
|
remainder < diff && delta - remainder >= exp &&
|
||||||
|
(remainder + exp < diff || diff - remainder > remainder + exp - diff)) {
|
||||||
--buf[size - 1];
|
--buf[size - 1];
|
||||||
remainder += exp;
|
remainder += exp;
|
||||||
}
|
}
|
||||||
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) {
|
||||||
@ -531,11 +541,11 @@ FMT_FUNC bool grisu2_gen_digits(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_CLANG_VERSION
|
#if FMT_CLANG_VERSION
|
||||||
# define FMT_FALLTHROUGH [[clang::fallthrough]];
|
# define FMT_FALLTHROUGH [[clang::fallthrough]];
|
||||||
#elif FMT_GCC_VERSION >= 700
|
#elif FMT_GCC_VERSION >= 700
|
||||||
# define FMT_FALLTHROUGH [[gnu::fallthrough]];
|
# define FMT_FALLTHROUGH [[gnu::fallthrough]];
|
||||||
#else
|
#else
|
||||||
# define FMT_FALLTHROUGH
|
# define FMT_FALLTHROUGH
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct gen_digits_params {
|
struct gen_digits_params {
|
||||||
@ -546,19 +556,18 @@ struct gen_digits_params {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct prettify_handler {
|
struct prettify_handler {
|
||||||
char *data;
|
char* data;
|
||||||
ptrdiff_t size;
|
ptrdiff_t size;
|
||||||
buffer &buf;
|
buffer& buf;
|
||||||
|
|
||||||
explicit prettify_handler(buffer &b, ptrdiff_t n)
|
explicit prettify_handler(buffer& b, ptrdiff_t n)
|
||||||
: data(b.data()), size(n), buf(b) {}
|
: data(b.data()), size(n), buf(b) {}
|
||||||
~prettify_handler() {
|
~prettify_handler() {
|
||||||
assert(buf.size() >= to_unsigned(size));
|
assert(buf.size() >= to_unsigned(size));
|
||||||
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('-');
|
||||||
@ -595,11 +603,11 @@ FMT_FUNC void write_exponent(int exp, Handler &&h) {
|
|||||||
if (exp >= 100) {
|
if (exp >= 100) {
|
||||||
h.append(static_cast<char>('0' + exp / 100));
|
h.append(static_cast<char>('0' + exp / 100));
|
||||||
exp %= 100;
|
exp %= 100;
|
||||||
const char *d = data::DIGITS + exp * 2;
|
const char* d = data::DIGITS + exp * 2;
|
||||||
h.append(d[0]);
|
h.append(d[0]);
|
||||||
h.append(d[1]);
|
h.append(d[1]);
|
||||||
} else {
|
} else {
|
||||||
const char *d = data::DIGITS + exp * 2;
|
const char* d = data::DIGITS + exp * 2;
|
||||||
h.append(d[0]);
|
h.append(d[0]);
|
||||||
h.append(d[1]);
|
h.append(d[1]);
|
||||||
}
|
}
|
||||||
@ -607,7 +615,7 @@ FMT_FUNC void write_exponent(int exp, Handler &&h) {
|
|||||||
|
|
||||||
struct fill {
|
struct fill {
|
||||||
size_t n;
|
size_t n;
|
||||||
void operator()(char *buf) const {
|
void operator()(char* buf) const {
|
||||||
buf[0] = '0';
|
buf[0] = '0';
|
||||||
buf[1] = '.';
|
buf[1] = '.';
|
||||||
std::uninitialized_fill_n(buf + 2, n, '0');
|
std::uninitialized_fill_n(buf + 2, n, '0');
|
||||||
@ -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 ¶ms,
|
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 ¶ms,
|
|||||||
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; }
|
||||||
@ -670,15 +676,16 @@ struct char_counter {
|
|||||||
// Converts format specifiers into parameters for digit generation and computes
|
// Converts format specifiers into parameters for digit generation and computes
|
||||||
// output buffer size for a number in the range [pow(10, exp - 1), pow(10, exp)
|
// output buffer size for a number in the range [pow(10, exp - 1), pow(10, exp)
|
||||||
// or 0 if exp == 1.
|
// or 0 if exp == 1.
|
||||||
FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,
|
FMT_FUNC gen_digits_params process_specs(const core_format_specs& specs,
|
||||||
int exp, buffer &buf) {
|
int exp, buffer& buf) {
|
||||||
auto params = gen_digits_params();
|
auto params = gen_digits_params();
|
||||||
int num_digits = specs.precision >= 0 ? specs.precision : 6;
|
int num_digits = specs.precision >= 0 ? specs.precision : 6;
|
||||||
switch (specs.type) {
|
switch (specs.type) {
|
||||||
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':
|
||||||
@ -713,7 +719,7 @@ FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,
|
|||||||
|
|
||||||
template <typename Double>
|
template <typename Double>
|
||||||
FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
|
FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
|
||||||
grisu2_format(Double value, buffer &buf, core_format_specs specs) {
|
grisu2_format(Double value, buffer& buf, core_format_specs specs) {
|
||||||
FMT_ASSERT(value >= 0, "value is negative");
|
FMT_ASSERT(value >= 0, "value is negative");
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
gen_digits_params params = process_specs(specs, 1, buf);
|
gen_digits_params params = process_specs(specs, 1, buf);
|
||||||
@ -728,13 +734,13 @@ FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
|
|||||||
fp_value.compute_boundaries(lower, upper);
|
fp_value.compute_boundaries(lower, upper);
|
||||||
|
|
||||||
// Find a cached power of 10 close to 1 / upper and use it to scale upper.
|
// Find a cached power of 10 close to 1 / upper and use it to scale upper.
|
||||||
const int min_exp = -60; // alpha in Grisu.
|
const int min_exp = -60; // alpha in Grisu.
|
||||||
int cached_exp = 0; // K in Grisu.
|
int cached_exp = 0; // K in Grisu.
|
||||||
auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
|
auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
|
||||||
min_exp - (upper.e + fp::significand_size), cached_exp);
|
min_exp - (upper.e + fp::significand_size), cached_exp);
|
||||||
cached_exp = -cached_exp;
|
cached_exp = -cached_exp;
|
||||||
upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
|
upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
|
||||||
--upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
|
--upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
|
||||||
fp one(1ull << -upper.e, upper.e);
|
fp one(1ull << -upper.e, upper.e);
|
||||||
// hi (p1 in Grisu) contains the most significant digits of scaled_upper.
|
// hi (p1 in Grisu) contains the most significant digits of scaled_upper.
|
||||||
// hi = floor(upper / one).
|
// hi = floor(upper / one).
|
||||||
@ -744,9 +750,9 @@ FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
|
|||||||
fp_value.normalize();
|
fp_value.normalize();
|
||||||
fp scaled_value = fp_value * cached_pow;
|
fp scaled_value = fp_value * cached_pow;
|
||||||
lower = lower * cached_pow; // \tilde{M}^- in Grisu.
|
lower = lower * cached_pow; // \tilde{M}^- in Grisu.
|
||||||
++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
|
++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
|
||||||
uint64_t delta = upper.f - lower.f;
|
uint64_t delta = upper.f - lower.f;
|
||||||
fp diff = upper - scaled_value; // wp_w in Grisu.
|
fp diff = upper - scaled_value; // wp_w in Grisu.
|
||||||
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
|
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
|
||||||
// lo = supper % one.
|
// lo = supper % one.
|
||||||
uint64_t lo = upper.f & (one.f - 1);
|
uint64_t lo = upper.f & (one.f - 1);
|
||||||
@ -761,29 +767,27 @@ FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Double>
|
template <typename Double>
|
||||||
void sprintf_format(Double value, internal::buffer &buf,
|
void sprintf_format(Double value, internal::buffer& buf,
|
||||||
core_format_specs spec) {
|
core_format_specs spec) {
|
||||||
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
|
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
|
||||||
FMT_ASSERT(buf.capacity() != 0, "empty buffer");
|
FMT_ASSERT(buf.capacity() != 0, "empty buffer");
|
||||||
|
|
||||||
// Build format string.
|
// Build format string.
|
||||||
enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
|
enum { MAX_FORMAT_SIZE = 10 }; // longest format: %#-*.*Lg
|
||||||
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';
|
||||||
|
|
||||||
// Format using snprintf.
|
// Format using snprintf.
|
||||||
char *start = FMT_NULL;
|
char* start = FMT_NULL;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
std::size_t buffer_size = buf.capacity();
|
std::size_t buffer_size = buf.capacity();
|
||||||
start = &buf[0];
|
start = &buf[0];
|
||||||
@ -819,28 +823,25 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
|
FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
|
||||||
if (int error_code = convert(s)) {
|
if (int error_code = convert(s)) {
|
||||||
FMT_THROW(windows_error(error_code,
|
FMT_THROW(windows_error(error_code,
|
||||||
"cannot convert string from UTF-16 to UTF-8"));
|
"cannot convert string from UTF-16 to UTF-8"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,39 +850,38 @@ 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));
|
||||||
std::runtime_error &base = *this;
|
std::runtime_error& base = *this;
|
||||||
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,19 +897,20 @@ 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);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char *system_message = &buf[0];
|
char* system_message = &buf[0];
|
||||||
int result = safe_strerror(error_code, system_message, buf.size());
|
int result = safe_strerror(error_code, system_message, buf.size());
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
writer w(out);
|
writer w(out);
|
||||||
@ -922,34 +923,35 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC void internal::error_handler::on_error(const char *message) {
|
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
|
||||||
|
|
||||||
FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
|
FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
internal::vformat_to(buffer, format_str,
|
internal::vformat_to(buffer, format_str,
|
||||||
basic_format_args<buffer_context<char>::type>(args));
|
basic_format_args<buffer_context<char>::type>(args));
|
||||||
std::fwrite(buffer.data(), 1, buffer.size(), f);
|
std::fwrite(buffer.data(), 1, buffer.size(), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
|
FMT_FUNC void vprint(std::FILE* f, wstring_view format_str, wformat_args args) {
|
||||||
wmemory_buffer buffer;
|
wmemory_buffer buffer;
|
||||||
internal::vformat_to(buffer, format_str, args);
|
internal::vformat_to(buffer, format_str, args);
|
||||||
std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
|
std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
|
||||||
@ -966,7 +968,7 @@ FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
|
|||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# pragma warning(pop)
|
# pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // FMT_FORMAT_INL_H_
|
#endif // FMT_FORMAT_INL_H_
|
||||||
|
1542
include/fmt/format.h
1542
include/fmt/format.h
File diff suppressed because it is too large
Load Diff
@ -8,63 +8,65 @@
|
|||||||
#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
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
typename buffer_context<Char>::type::iterator vformat_to(
|
typename buffer_context<Char>::type::iterator vformat_to(
|
||||||
const std::locale &loc, basic_buffer<Char> &buf,
|
const std::locale& loc, basic_buffer<Char>& buf,
|
||||||
basic_string_view<Char> format_str,
|
basic_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>
|
||||||
std::basic_string<Char> vformat(
|
std::basic_string<Char> vformat(
|
||||||
const std::locale &loc, basic_string_view<Char> format_str,
|
const std::locale& loc, basic_string_view<Char> format_str,
|
||||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
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(
|
||||||
const std::locale &loc, const S &format_str,
|
const std::locale& loc, const S& format_str,
|
||||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||||
return internal::vformat(loc, to_string_view(format_str), args);
|
return internal::vformat(loc, to_string_view(format_str), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
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...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename String, typename OutputIt, typename... Args>
|
template <typename String, typename OutputIt, typename... Args>
|
||||||
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
|
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
|
||||||
OutputIt>::type
|
OutputIt>::type
|
||||||
vformat_to(OutputIt out, const std::locale &loc, const String &format_str,
|
vformat_to(OutputIt out, const std::locale& loc, const String& format_str,
|
||||||
typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
|
typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
|
||||||
typedef output_range<OutputIt, FMT_CHAR(String)> range;
|
typedef output_range<OutputIt, FMT_CHAR(String)> range;
|
||||||
return vformat_to<arg_formatter<range>>(
|
return vformat_to<arg_formatter<range>>(
|
||||||
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
|
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
format_to(OutputIt out, const std::locale &loc, const S &format_str,
|
OutputIt>::type
|
||||||
const Args &... args) {
|
format_to(OutputIt out, const std::locale& loc, const S& format_str,
|
||||||
|
const Args&... args) {
|
||||||
internal::check_format_string<Args...>(format_str);
|
internal::check_format_string<Args...>(format_str);
|
||||||
typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;
|
typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;
|
||||||
format_arg_store<context, Args...> as{args...};
|
format_arg_store<context, Args...> as{args...};
|
||||||
|
@ -8,22 +8,21 @@
|
|||||||
#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;
|
||||||
|
|
||||||
basic_buffer<Char> &buffer_;
|
basic_buffer<Char>& buffer_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
formatbuf(basic_buffer<Char> &buffer) : buffer_(buffer) {}
|
formatbuf(basic_buffer<Char>& buffer) : buffer_(buffer) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// The put-area is actually always empty. This makes the implementation
|
// The put-area is actually always empty. This makes the implementation
|
||||||
@ -39,31 +38,30 @@ class formatbuf : public std::basic_streambuf<Char> {
|
|||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
|
std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE {
|
||||||
buffer_.append(s, s + count);
|
buffer_.append(s, s + count);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
@ -73,8 +71,8 @@ class is_streamable {
|
|||||||
|
|
||||||
// Write the content of buf to os.
|
// Write the content of buf to os.
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) {
|
void write(std::basic_ostream<Char>& os, basic_buffer<Char>& buf) {
|
||||||
const Char *data = buf.data();
|
const Char* data = buf.data();
|
||||||
typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;
|
typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;
|
||||||
UnsignedStreamSize size = buf.size();
|
UnsignedStreamSize size = buf.size();
|
||||||
UnsignedStreamSize max_size =
|
UnsignedStreamSize max_size =
|
||||||
@ -88,7 +86,7 @@ void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename T>
|
template <typename Char, typename T>
|
||||||
void format_value(basic_buffer<Char> &buffer, const T &value) {
|
void format_value(basic_buffer<Char>& buffer, const T& value) {
|
||||||
internal::formatbuf<Char> format_buf(buffer);
|
internal::formatbuf<Char> format_buf(buffer);
|
||||||
std::basic_ostream<Char> output(&format_buf);
|
std::basic_ostream<Char> output(&format_buf);
|
||||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||||
@ -99,24 +97,21 @@ 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 =
|
!internal::is_streamable<T, Char>::value;
|
||||||
convert_to_int<T, Char, int>::value &&
|
|
||||||
!internal::is_streamable<T, Char>::value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Formats an object of type T that has an overloaded ostream operator<<.
|
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||||
template <typename T, typename Char>
|
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;
|
||||||
internal::format_value(buffer, value);
|
internal::format_value(buffer, value);
|
||||||
basic_string_view<Char> str(buffer.data(), buffer.size());
|
basic_string_view<Char> str(buffer.data(), buffer.size());
|
||||||
@ -125,9 +120,9 @@ 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);
|
||||||
internal::write(os, buffer);
|
internal::write(os, buffer);
|
||||||
@ -142,9 +137,9 @@ 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);
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
||||||
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
|
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
|
||||||
# undef __STRICT_ANSI__
|
# undef __STRICT_ANSI__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -22,42 +22,42 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#if defined __APPLE__ || defined(__FreeBSD__)
|
#if defined __APPLE__ || defined(__FreeBSD__)
|
||||||
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
|
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
#ifndef FMT_POSIX
|
#ifndef FMT_POSIX
|
||||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
// Fix warnings about deprecated symbols.
|
// Fix warnings about deprecated symbols.
|
||||||
# define FMT_POSIX(call) _##call
|
# define FMT_POSIX(call) _##call
|
||||||
# else
|
# else
|
||||||
# define FMT_POSIX(call) call
|
# define FMT_POSIX(call) call
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
|
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
|
||||||
#ifdef FMT_SYSTEM
|
#ifdef FMT_SYSTEM
|
||||||
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
|
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
|
||||||
#else
|
#else
|
||||||
# define FMT_SYSTEM(call) call
|
# define FMT_SYSTEM(call) call
|
||||||
# ifdef _WIN32
|
# ifdef _WIN32
|
||||||
// Fix warnings about deprecated symbols.
|
// Fix warnings about deprecated symbols.
|
||||||
# define FMT_POSIX_CALL(call) ::_##call
|
# define FMT_POSIX_CALL(call) ::_##call
|
||||||
# else
|
# else
|
||||||
# define FMT_POSIX_CALL(call) ::call
|
# define FMT_POSIX_CALL(call) ::call
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Retries the expression while it evaluates to error_result and errno
|
// Retries the expression while it evaluates to error_result and errno
|
||||||
// equals to EINTR.
|
// equals to EINTR.
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
# define FMT_RETRY_VAL(result, expression, error_result) \
|
# define FMT_RETRY_VAL(result, expression, error_result) \
|
||||||
do { \
|
do { \
|
||||||
result = (expression); \
|
result = (expression); \
|
||||||
} while (result == error_result && errno == EINTR)
|
} while (result == error_result && errno == EINTR)
|
||||||
#else
|
#else
|
||||||
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
|
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
|
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
|
||||||
@ -89,24 +89,23 @@ 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_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Constructs a string reference object from a C string. */
|
/** Constructs a string reference object from a C string. */
|
||||||
basic_cstring_view(const Char *s) : data_(s) {}
|
basic_cstring_view(const Char* s) : data_(s) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Constructs a string reference from an ``std::string`` object.
|
Constructs a string reference from an ``std::string`` object.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
basic_cstring_view(const std::basic_string<Char> &s) : data_(s.c_str()) {}
|
basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
|
||||||
|
|
||||||
/** Returns the pointer to a C string. */
|
/** Returns the pointer to a C string. */
|
||||||
const Char *c_str() const { return data_; }
|
const Char* c_str() const { return data_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef basic_cstring_view<char> cstring_view;
|
typedef basic_cstring_view<char> cstring_view;
|
||||||
@ -126,11 +125,11 @@ class error_code {
|
|||||||
// A buffered file.
|
// A buffered file.
|
||||||
class buffered_file {
|
class buffered_file {
|
||||||
private:
|
private:
|
||||||
FILE *file_;
|
FILE* file_;
|
||||||
|
|
||||||
friend class file;
|
friend class file;
|
||||||
|
|
||||||
explicit buffered_file(FILE *f) : file_(f) {}
|
explicit buffered_file(FILE* f) : file_(f) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructs a buffered_file object which doesn't represent any file.
|
// Constructs a buffered_file object which doesn't represent any file.
|
||||||
@ -140,16 +139,15 @@ class buffered_file {
|
|||||||
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffered_file& operator=(buffered_file &&other) {
|
buffered_file& operator=(buffered_file&& other) {
|
||||||
close();
|
close();
|
||||||
file_ = other.file_;
|
file_ = other.file_;
|
||||||
other.file_ = FMT_NULL;
|
other.file_ = FMT_NULL;
|
||||||
@ -163,18 +161,18 @@ class buffered_file {
|
|||||||
FMT_API void close();
|
FMT_API void close();
|
||||||
|
|
||||||
// Returns the pointer to a FILE object representing this file.
|
// Returns the pointer to a FILE object representing this file.
|
||||||
FILE *get() const FMT_NOEXCEPT { return file_; }
|
FILE* get() const FMT_NOEXCEPT { return file_; }
|
||||||
|
|
||||||
// We place parentheses around fileno to workaround a bug in some versions
|
// We place parentheses around fileno to workaround a bug in some versions
|
||||||
// of MinGW that define fileno as a macro.
|
// of MinGW that define fileno as a macro.
|
||||||
FMT_API int (fileno)() const;
|
FMT_API int(fileno)() const;
|
||||||
|
|
||||||
void vprint(string_view format_str, format_args args) {
|
void vprint(string_view format_str, format_args args) {
|
||||||
fmt::vprint(file_, format_str, args);
|
fmt::vprint(file_, format_str, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline void print(string_view format_str, const Args & ... args) {
|
inline void print(string_view format_str, const Args&... args) {
|
||||||
vprint(format_str, make_format_args(args...));
|
vprint(format_str, make_format_args(args...));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -195,9 +193,9 @@ class file {
|
|||||||
public:
|
public:
|
||||||
// Possible values for the oflag argument to the constructor.
|
// Possible values for the oflag argument to the constructor.
|
||||||
enum {
|
enum {
|
||||||
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
|
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
|
||||||
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
||||||
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
|
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructs a file object which doesn't represent any file.
|
// Constructs a file object which doesn't represent any file.
|
||||||
@ -207,15 +205,13 @@ class file {
|
|||||||
FMT_API file(cstring_view path, int oflag);
|
FMT_API file(cstring_view path, int oflag);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
file(const file &) = delete;
|
file(const file&) = delete;
|
||||||
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();
|
||||||
fd_ = other.fd_;
|
fd_ = other.fd_;
|
||||||
other.fd_ = -1;
|
other.fd_ = -1;
|
||||||
@ -236,10 +232,10 @@ class file {
|
|||||||
FMT_API long long size() const;
|
FMT_API long long size() const;
|
||||||
|
|
||||||
// Attempts to read count bytes from the file into the specified buffer.
|
// Attempts to read count bytes from the file into the specified buffer.
|
||||||
FMT_API std::size_t read(void *buffer, std::size_t count);
|
FMT_API std::size_t read(void* buffer, std::size_t count);
|
||||||
|
|
||||||
// Attempts to write count bytes from the specified buffer to the file.
|
// Attempts to write count bytes from the specified buffer to the file.
|
||||||
FMT_API std::size_t write(const void *buffer, std::size_t count);
|
FMT_API std::size_t write(const void* buffer, std::size_t count);
|
||||||
|
|
||||||
// Duplicates a file descriptor with the dup function and returns
|
// Duplicates a file descriptor with the dup function and returns
|
||||||
// the duplicate as a file object.
|
// the duplicate as a file object.
|
||||||
@ -251,59 +247,56 @@ class file {
|
|||||||
|
|
||||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||||
// necessary.
|
// necessary.
|
||||||
FMT_API void dup2(int fd, error_code &ec) FMT_NOEXCEPT;
|
FMT_API void dup2(int fd, error_code& ec) FMT_NOEXCEPT;
|
||||||
|
|
||||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||||
// and writing respectively.
|
// and writing respectively.
|
||||||
FMT_API static void pipe(file &read_end, file &write_end);
|
FMT_API static void pipe(file& read_end, file& write_end);
|
||||||
|
|
||||||
// Creates a buffered_file object associated with this file and detaches
|
// Creates a buffered_file object associated with this file and detaches
|
||||||
// this file object from the file.
|
// this file object from the file.
|
||||||
FMT_API buffered_file fdopen(const char *mode);
|
FMT_API buffered_file fdopen(const char* mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns the memory page size.
|
// Returns the memory page size.
|
||||||
long getpagesize();
|
long getpagesize();
|
||||||
|
|
||||||
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
|
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
|
||||||
!defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \
|
!defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \
|
||||||
!defined(__NEWLIB_H__)
|
!defined(__NEWLIB_H__)
|
||||||
# define FMT_LOCALE
|
# define FMT_LOCALE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef FMT_LOCALE
|
#ifdef FMT_LOCALE
|
||||||
// A "C" numeric locale.
|
// A "C" numeric locale.
|
||||||
class Locale {
|
class Locale {
|
||||||
private:
|
private:
|
||||||
# ifdef _MSC_VER
|
# ifdef _MSC_VER
|
||||||
typedef _locale_t locale_t;
|
typedef _locale_t locale_t;
|
||||||
|
|
||||||
enum { LC_NUMERIC_MASK = LC_NUMERIC };
|
enum { LC_NUMERIC_MASK = LC_NUMERIC };
|
||||||
|
|
||||||
static locale_t newlocale(int category_mask, const char *locale, locale_t) {
|
static locale_t newlocale(int category_mask, const char* locale, locale_t) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
locale_t locale_;
|
locale_t locale_;
|
||||||
|
|
||||||
Locale(const Locale &) = delete;
|
Locale(const Locale&) = delete;
|
||||||
void operator=(const Locale &) = delete;
|
void operator=(const Locale&) = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
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_); }
|
||||||
|
|
||||||
@ -311,8 +304,8 @@ class Locale {
|
|||||||
|
|
||||||
// Converts string to floating-point number and advances str past the end
|
// Converts string to floating-point number and advances str past the end
|
||||||
// of the parsed input.
|
// of the parsed input.
|
||||||
double strtod(const char *&str) const {
|
double strtod(const char*& str) const {
|
||||||
char *end = FMT_NULL;
|
char* end = FMT_NULL;
|
||||||
double result = strtod_l(str, &end, locale_);
|
double result = strtod_l(str, &end, locale_);
|
||||||
str = end;
|
str = end;
|
||||||
return result;
|
return result;
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
#define FMT_PREPARE_H_
|
#define FMT_PREPARE_H_
|
||||||
|
|
||||||
#ifndef FMT_HAS_CONSTRUCTIBLE_TRAITS
|
#ifndef FMT_HAS_CONSTRUCTIBLE_TRAITS
|
||||||
# define FMT_HAS_CONSTRUCTIBLE_TRAITS \
|
# define FMT_HAS_CONSTRUCTIBLE_TRAITS \
|
||||||
(FMT_GCC_VERSION >= 407 || FMT_CLANG_VERSION || FMT_MSC_VER)
|
(FMT_GCC_VERSION >= 407 || FMT_CLANG_VERSION || FMT_MSC_VER)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
@ -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,23 +100,24 @@ 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 {
|
||||||
template <typename Char, typename PartsContainer>
|
template <typename Char, typename PartsContainer>
|
||||||
class format_preparation_handler : public internal::error_handler {
|
class format_preparation_handler : public internal::error_handler {
|
||||||
private:
|
private:
|
||||||
typedef format_part<Char> part;
|
typedef format_part<Char> part;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef internal::null_terminating_iterator<Char> iterator;
|
typedef internal::null_terminating_iterator<Char> iterator;
|
||||||
|
|
||||||
FMT_CONSTEXPR format_preparation_handler(basic_string_view<Char> format,
|
FMT_CONSTEXPR format_preparation_handler(basic_string_view<Char> format,
|
||||||
PartsContainer &parts)
|
PartsContainer& parts)
|
||||||
: parts_(parts), format_(format), parse_context_(format) {}
|
: parts_(parts), format_(format), parse_context_(format) {}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_text(const Char *begin, const Char *end) {
|
FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
|
||||||
if (begin == end) {
|
if (begin == end) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -139,20 +141,19 @@ public:
|
|||||||
parts_.add(part(arg_id));
|
parts_.add(part(arg_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_replacement_field(const Char *ptr) {
|
FMT_CONSTEXPR void on_replacement_field(const Char* ptr) {
|
||||||
auto last_part = parts_.last();
|
auto last_part = parts_.last();
|
||||||
last_part.end_of_argument_id = ptr - format_.begin();
|
last_part.end_of_argument_id = ptr - format_.begin();
|
||||||
parts_.substitute_last(last_part);
|
parts_.substitute_last(last_part);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR const Char *on_format_specs(const Char *begin,
|
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
|
||||||
const Char *end) {
|
const Char* end) {
|
||||||
const auto specs_offset = to_unsigned(begin - format_.begin());
|
const auto specs_offset = to_unsigned(begin - format_.begin());
|
||||||
|
|
||||||
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 != '}') {
|
||||||
@ -176,7 +177,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PartsContainer &parts_;
|
PartsContainer& parts_;
|
||||||
basic_string_view<Char> format_;
|
basic_string_view<Char> format_;
|
||||||
basic_parse_context<Char> parse_context_;
|
basic_parse_context<Char> parse_context_;
|
||||||
};
|
};
|
||||||
@ -193,7 +194,7 @@ class prepared_format {
|
|||||||
|
|
||||||
prepared_format() = delete;
|
prepared_format() = delete;
|
||||||
|
|
||||||
std::size_t formatted_size(const Args &... args) const {
|
std::size_t formatted_size(const Args&... args) const {
|
||||||
const auto it = this->format_to(counting_iterator<char_type>(), args...);
|
const auto it = this->format_to(counting_iterator<char_type>(), args...);
|
||||||
return it.count();
|
return it.count();
|
||||||
}
|
}
|
||||||
@ -201,10 +202,10 @@ class prepared_format {
|
|||||||
template <typename OutputIt>
|
template <typename OutputIt>
|
||||||
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
|
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
|
||||||
format_to_n_result<OutputIt>>::type
|
format_to_n_result<OutputIt>>::type
|
||||||
format_to_n(OutputIt out, unsigned n, const Args &... args) const {
|
format_to_n(OutputIt out, unsigned n, const Args&... args) const {
|
||||||
format_arg_store<typename format_to_n_context<OutputIt, char_type>::type,
|
format_arg_store<typename format_to_n_context<OutputIt, char_type>::type,
|
||||||
Args...>
|
Args...>
|
||||||
as(args...);
|
as(args...);
|
||||||
|
|
||||||
typedef truncating_iterator<OutputIt> trunc_it;
|
typedef truncating_iterator<OutputIt> trunc_it;
|
||||||
typedef output_range<trunc_it, char_type> range;
|
typedef output_range<trunc_it, char_type> range;
|
||||||
@ -214,7 +215,7 @@ class prepared_format {
|
|||||||
return {it.base(), it.count()};
|
return {it.base(), it.count()};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::basic_string<char_type> format(const Args &... args) const {
|
std::basic_string<char_type> format(const Args&... args) const {
|
||||||
basic_memory_buffer<char_type> buffer;
|
basic_memory_buffer<char_type> buffer;
|
||||||
typedef back_insert_range<internal::basic_buffer<char_type>> range;
|
typedef back_insert_range<internal::basic_buffer<char_type>> range;
|
||||||
this->vformat_to(range(buffer), *checked_args(format_, args...));
|
this->vformat_to(range(buffer), *checked_args(format_, args...));
|
||||||
@ -225,7 +226,7 @@ class prepared_format {
|
|||||||
inline typename std::enable_if<is_contiguous<Container>::value,
|
inline typename std::enable_if<is_contiguous<Container>::value,
|
||||||
std::back_insert_iterator<Container>>::type
|
std::back_insert_iterator<Container>>::type
|
||||||
format_to(std::back_insert_iterator<Container> out,
|
format_to(std::back_insert_iterator<Container> out,
|
||||||
const Args &... args) const {
|
const Args&... args) const {
|
||||||
internal::container_buffer<Container> buffer(internal::get_container(out));
|
internal::container_buffer<Container> buffer(internal::get_container(out));
|
||||||
typedef back_insert_range<internal::basic_buffer<char_type>> range;
|
typedef back_insert_range<internal::basic_buffer<char_type>> range;
|
||||||
this->vformat_to(range(buffer), *checked_args(format_, args...));
|
this->vformat_to(range(buffer), *checked_args(format_, args...));
|
||||||
@ -233,7 +234,7 @@ class prepared_format {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt>
|
template <typename OutputIt>
|
||||||
inline OutputIt format_to(OutputIt out, const Args &... args) const {
|
inline OutputIt format_to(OutputIt out, const Args&... args) const {
|
||||||
typedef typename format_context_t<OutputIt, char_type>::type context;
|
typedef typename format_context_t<OutputIt, char_type>::type context;
|
||||||
typedef output_range<OutputIt, char_type> range;
|
typedef output_range<OutputIt, char_type> range;
|
||||||
format_arg_store<context, Args...> as(args...);
|
format_arg_store<context, Args...> as(args...);
|
||||||
@ -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...));
|
||||||
}
|
}
|
||||||
@ -255,16 +255,16 @@ class prepared_format {
|
|||||||
const auto format_view = internal::to_string_view(format_);
|
const auto format_view = internal::to_string_view(format_);
|
||||||
Context ctx(out.begin(), format_view, args);
|
Context ctx(out.begin(), format_view, args);
|
||||||
|
|
||||||
const auto &parts = parts_provider_.parts();
|
const auto& parts = parts_provider_.parts();
|
||||||
for (auto part_it = parts.begin(); part_it != parts.end(); ++part_it) {
|
for (auto part_it = parts.begin(); part_it != parts.end(); ++part_it) {
|
||||||
const auto &part = *part_it;
|
const auto& part = *part_it;
|
||||||
const auto &value = part.val;
|
const auto& value = part.val;
|
||||||
|
|
||||||
switch (part.which) {
|
switch (part.which) {
|
||||||
case format_part_t::which_value::text: {
|
case format_part_t::which_value::text: {
|
||||||
const auto text = value.text.to_view(format_view);
|
const auto text = value.text.to_view(format_view);
|
||||||
auto out = ctx.out();
|
auto out = ctx.out();
|
||||||
auto &&it = internal::reserve(out, text.size());
|
auto&& it = internal::reserve(out, text.size());
|
||||||
it = std::copy_n(text.begin(), text.size(), it);
|
it = std::copy_n(text.begin(), text.size(), it);
|
||||||
ctx.advance_to(out);
|
ctx.advance_to(out);
|
||||||
} break;
|
} break;
|
||||||
@ -280,7 +280,7 @@ class prepared_format {
|
|||||||
format_arg<Range>(ctx, named_arg_id);
|
format_arg<Range>(ctx, named_arg_id);
|
||||||
} break;
|
} break;
|
||||||
case format_part_t::which_value::specification: {
|
case format_part_t::which_value::specification: {
|
||||||
const auto &arg_id_value = value.spec.arg_id.val;
|
const auto& arg_id_value = value.spec.arg_id.val;
|
||||||
const auto arg =
|
const auto arg =
|
||||||
value.spec.arg_id.which ==
|
value.spec.arg_id.which ==
|
||||||
format_part_t::argument_id::which_arg_id::index
|
format_part_t::argument_id::which_arg_id::index
|
||||||
@ -306,15 +306,15 @@ class prepared_format {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
void advance_parse_context_to_specification(Context &ctx,
|
void advance_parse_context_to_specification(Context& ctx,
|
||||||
const format_part_t &part) const {
|
const format_part_t& part) const {
|
||||||
const auto view = to_string_view(format_);
|
const auto view = to_string_view(format_);
|
||||||
const auto specification_begin = view.data() + part.end_of_argument_id;
|
const auto specification_begin = view.data() + part.end_of_argument_id;
|
||||||
ctx.parse_context().advance_to(specification_begin);
|
ctx.parse_context().advance_to(specification_begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Range, typename Context, typename Id>
|
template <typename Range, typename Context, typename Id>
|
||||||
void format_arg(Context &ctx, Id arg_id) const {
|
void format_arg(Context& ctx, Id arg_id) const {
|
||||||
ctx.parse_context().check_arg_id(arg_id);
|
ctx.parse_context().check_arg_id(arg_id);
|
||||||
const auto stopped_at =
|
const auto stopped_at =
|
||||||
visit_format_arg(arg_formatter<Range>(ctx), ctx.get_arg(arg_id));
|
visit_format_arg(arg_formatter<Range>(ctx), ctx.get_arg(arg_id));
|
||||||
@ -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) {
|
||||||
@ -343,23 +343,23 @@ class prepared_format {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Format format_;
|
Format format_;
|
||||||
PreparedPartsProvider parts_provider_;
|
PreparedPartsProvider parts_provider_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Format> class compiletime_prepared_parts_type_provider {
|
template <typename Format> class compiletime_prepared_parts_type_provider {
|
||||||
private:
|
private:
|
||||||
typedef FMT_CHAR(Format) char_type;
|
typedef FMT_CHAR(Format) char_type;
|
||||||
|
|
||||||
class count_handler {
|
class count_handler {
|
||||||
private:
|
private:
|
||||||
typedef internal::null_terminating_iterator<char_type> iterator;
|
typedef internal::null_terminating_iterator<char_type> iterator;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FMT_CONSTEXPR count_handler() : counter_(0u) {}
|
FMT_CONSTEXPR count_handler() : counter_(0u) {}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_text(const char_type *begin, const char_type *end) {
|
FMT_CONSTEXPR void on_text(const char_type* begin, const char_type* end) {
|
||||||
if (begin != end) {
|
if (begin != end) {
|
||||||
++counter_;
|
++counter_;
|
||||||
}
|
}
|
||||||
@ -369,20 +369,20 @@ private:
|
|||||||
FMT_CONSTEXPR void on_arg_id(unsigned) { ++counter_; }
|
FMT_CONSTEXPR void on_arg_id(unsigned) { ++counter_; }
|
||||||
FMT_CONSTEXPR void on_arg_id(basic_string_view<char_type>) { ++counter_; }
|
FMT_CONSTEXPR void on_arg_id(basic_string_view<char_type>) { ++counter_; }
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_replacement_field(const char_type *) {}
|
FMT_CONSTEXPR void on_replacement_field(const char_type*) {}
|
||||||
|
|
||||||
FMT_CONSTEXPR const char_type *on_format_specs(const char_type *begin,
|
FMT_CONSTEXPR const char_type* on_format_specs(const char_type* begin,
|
||||||
const char_type *end) {
|
const char_type* end) {
|
||||||
return find_matching_brace(begin, end);
|
return find_matching_brace(begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_error(const char *) {}
|
FMT_CONSTEXPR void on_error(const char*) {}
|
||||||
|
|
||||||
FMT_CONSTEXPR unsigned result() const { return counter_; }
|
FMT_CONSTEXPR unsigned result() const { return counter_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FMT_CONSTEXPR const char_type *find_matching_brace(const char_type *begin,
|
FMT_CONSTEXPR const char_type* find_matching_brace(const char_type* begin,
|
||||||
const char_type *end) {
|
const char_type* end) {
|
||||||
FMT_CONSTEXPR_DECL const basic_string_view<char_type> text = Format{};
|
FMT_CONSTEXPR_DECL const basic_string_view<char_type> text = Format{};
|
||||||
unsigned braces_counter{0u};
|
unsigned braces_counter{0u};
|
||||||
for (; begin != end; ++begin) {
|
for (; begin != end; ++begin) {
|
||||||
@ -399,7 +399,7 @@ private:
|
|||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned counter_;
|
unsigned counter_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -425,13 +425,13 @@ private:
|
|||||||
|
|
||||||
FMT_CONSTEXPR format_parts_array() : arr{} {}
|
FMT_CONSTEXPR format_parts_array() : arr{} {}
|
||||||
|
|
||||||
FMT_CONSTEXPR value_type &operator[](unsigned ind) { return arr[ind]; }
|
FMT_CONSTEXPR value_type& operator[](unsigned ind) { return arr[ind]; }
|
||||||
|
|
||||||
FMT_CONSTEXPR const value_type *begin() const { return arr; }
|
FMT_CONSTEXPR const value_type* begin() const { return arr; }
|
||||||
|
|
||||||
FMT_CONSTEXPR const value_type *end() const { return begin() + N; }
|
FMT_CONSTEXPR const value_type* end() const { return begin() + N; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
value_type arr[N];
|
value_type arr[N];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -450,7 +450,7 @@ template <typename Parts> class compiletime_prepared_parts_collector {
|
|||||||
typedef typename Parts::value_type format_part;
|
typedef typename Parts::value_type format_part;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FMT_CONSTEXPR explicit compiletime_prepared_parts_collector(Parts &parts)
|
FMT_CONSTEXPR explicit compiletime_prepared_parts_collector(Parts& parts)
|
||||||
: parts_{parts}, counter_{0u} {}
|
: parts_{parts}, counter_{0u} {}
|
||||||
|
|
||||||
FMT_CONSTEXPR void add(format_part part) { parts_[counter_++] = part; }
|
FMT_CONSTEXPR void add(format_part part) { parts_[counter_++] = part; }
|
||||||
@ -462,7 +462,7 @@ template <typename Parts> class compiletime_prepared_parts_collector {
|
|||||||
FMT_CONSTEXPR format_part last() { return parts_[counter_ - 1]; }
|
FMT_CONSTEXPR format_part last() { return parts_[counter_ - 1]; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Parts &parts_;
|
Parts& parts_;
|
||||||
unsigned counter_;
|
unsigned counter_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -493,7 +493,7 @@ template <typename PartsContainer> class runtime_parts_provider {
|
|||||||
runtime_parts_provider(basic_string_view<Char> format)
|
runtime_parts_provider(basic_string_view<Char> format)
|
||||||
: parts_(prepare_parts<PartsContainer>(format)) {}
|
: parts_(prepare_parts<PartsContainer>(format)) {}
|
||||||
|
|
||||||
const PartsContainer &parts() const { return parts_; }
|
const PartsContainer& parts() const { return parts_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PartsContainer parts_;
|
PartsContainer parts_;
|
||||||
@ -505,7 +505,7 @@ struct compiletime_parts_provider {
|
|||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR compiletime_parts_provider(basic_string_view<Char>) {}
|
FMT_CONSTEXPR compiletime_parts_provider(basic_string_view<Char>) {}
|
||||||
|
|
||||||
const PartsContainer &parts() const {
|
const PartsContainer& parts() const {
|
||||||
static FMT_CONSTEXPR_DECL const PartsContainer prepared_parts =
|
static FMT_CONSTEXPR_DECL const PartsContainer prepared_parts =
|
||||||
prepare_compiletime_parts<PartsContainer>(
|
prepare_compiletime_parts<PartsContainer>(
|
||||||
internal::to_string_view(Format{}));
|
internal::to_string_view(Format{}));
|
||||||
@ -608,7 +608,7 @@ std::basic_string<Char> to_runtime_format(basic_string_view<Char> format) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
std::basic_string<Char> to_runtime_format(const Char *format) {
|
std::basic_string<Char> to_runtime_format(const Char* format) {
|
||||||
return std::basic_string<Char>(format);
|
return std::basic_string<Char>(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -685,17 +685,17 @@ auto do_prepare(runtime_format_tag, Format format) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Format, typename... Args>
|
template <typename Format, typename... Args>
|
||||||
FMT_CONSTEXPR auto do_prepare(compiletime_format_tag, const Format &format) {
|
FMT_CONSTEXPR auto do_prepare(compiletime_format_tag, const Format& format) {
|
||||||
return typename basic_prepared_format<Format, void, Args...>::type(format);
|
return typename basic_prepared_format<Format, void, Args...>::type(format);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
template <typename Format, typename... Args>
|
template <typename Format, typename... Args>
|
||||||
auto do_prepare(const Format &format)
|
auto do_prepare(const Format& format)
|
||||||
-> decltype(preparator<Format, Args...>::prepare(format)) {
|
-> decltype(preparator<Format, Args...>::prepare(format)) {
|
||||||
return preparator<Format, Args...>::prepare(format);
|
return preparator<Format, Args...>::prepare(format);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
template <typename Char, typename Container = std::vector<format_part<Char>>>
|
template <typename Char, typename Container = std::vector<format_part<Char>>>
|
||||||
struct parts_container {
|
struct parts_container {
|
||||||
@ -757,7 +757,7 @@ auto prepare(Format format) ->
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename... Args, typename Char>
|
template <typename... Args, typename Char>
|
||||||
auto prepare(const Char *format) ->
|
auto prepare(const Char* format) ->
|
||||||
typename internal::preparator<std::basic_string<Char>,
|
typename internal::preparator<std::basic_string<Char>,
|
||||||
Args...>::prepared_format_type {
|
Args...>::prepared_format_type {
|
||||||
return prepare<Args...>(internal::to_runtime_format(format));
|
return prepare<Args...>(internal::to_runtime_format(format));
|
||||||
|
@ -18,95 +18,91 @@ 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();
|
||||||
}
|
}
|
||||||
static bool fits_in_int(int) { return true; }
|
static bool fits_in_int(int) { return 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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// An argument visitor that returns true iff arg is a zero integer.
|
// An argument visitor that returns true iff arg is a zero integer.
|
||||||
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> {
|
||||||
private:
|
private:
|
||||||
typedef typename Context::char_type Char;
|
typedef typename Context::char_type Char;
|
||||||
|
|
||||||
basic_format_arg<Context> &arg_;
|
basic_format_arg<Context>& arg_;
|
||||||
typename Context::char_type type_;
|
typename Context::char_type type_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
arg_converter(basic_format_arg<Context> &arg, Char type)
|
arg_converter(basic_format_arg<Context>& arg, Char type)
|
||||||
: 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) {
|
||||||
arg_ = internal::make_arg<Context>(
|
arg_ = internal::make_arg<Context>(
|
||||||
static_cast<int>(static_cast<TargetType>(value)));
|
static_cast<int>(static_cast<TargetType>(value)));
|
||||||
} else {
|
} else {
|
||||||
typedef typename make_unsigned_or_bool<TargetType>::type Unsigned;
|
typedef typename make_unsigned_or_bool<TargetType>::type Unsigned;
|
||||||
arg_ = internal::make_arg<Context>(
|
arg_ = internal::make_arg<Context>(
|
||||||
static_cast<unsigned>(static_cast<Unsigned>(value)));
|
static_cast<unsigned>(static_cast<Unsigned>(value)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_signed) {
|
if (is_signed) {
|
||||||
@ -116,7 +112,7 @@ class arg_converter: public function<void> {
|
|||||||
arg_ = internal::make_arg<Context>(static_cast<long long>(value));
|
arg_ = internal::make_arg<Context>(static_cast<long long>(value));
|
||||||
} else {
|
} else {
|
||||||
arg_ = internal::make_arg<Context>(
|
arg_ = internal::make_arg<Context>(
|
||||||
static_cast<typename make_unsigned_or_bool<U>::type>(value));
|
static_cast<typename make_unsigned_or_bool<U>::type>(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,22 +128,21 @@ class arg_converter: public function<void> {
|
|||||||
// type depending on the type specifier: 'd' and 'i' - signed, other -
|
// type depending on the type specifier: 'd' and 'i' - signed, other -
|
||||||
// unsigned).
|
// unsigned).
|
||||||
template <typename T, typename Context, typename Char>
|
template <typename T, typename Context, typename Char>
|
||||||
void convert_arg(basic_format_arg<Context> &arg, Char type) {
|
void convert_arg(basic_format_arg<Context>& arg, Char type) {
|
||||||
visit_format_arg(arg_converter<T, Context>(arg, type), arg);
|
visit_format_arg(arg_converter<T, Context>(arg, type), arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
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));
|
||||||
}
|
}
|
||||||
@ -161,18 +156,18 @@ class char_converter: public function<void> {
|
|||||||
// Checks if an argument is a valid printf width specifier and sets
|
// Checks if an argument is a valid printf width specifier and sets
|
||||||
// left alignment if it is negative.
|
// left alignment if it is negative.
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
class printf_width_handler: public function<unsigned> {
|
class printf_width_handler : public function<unsigned> {
|
||||||
private:
|
private:
|
||||||
typedef basic_format_specs<Char> format_specs;
|
typedef basic_format_specs<Char> format_specs;
|
||||||
|
|
||||||
format_specs &spec_;
|
format_specs& spec_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit printf_width_handler(format_specs &spec) : spec_(spec) {}
|
explicit printf_width_handler(format_specs& spec) : spec_(spec) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<std::is_integral<T>::value, unsigned>::type
|
typename std::enable_if<std::is_integral<T>::value, unsigned>::type
|
||||||
operator()(T value) {
|
operator()(T value) {
|
||||||
typedef typename internal::int_traits<T>::main_type UnsignedType;
|
typedef typename internal::int_traits<T>::main_type UnsignedType;
|
||||||
UnsignedType width = static_cast<UnsignedType>(value);
|
UnsignedType width = static_cast<UnsignedType>(value);
|
||||||
if (internal::is_negative(value)) {
|
if (internal::is_negative(value)) {
|
||||||
@ -180,21 +175,20 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<!std::is_integral<T>::value, unsigned>::type
|
typename std::enable_if<!std::is_integral<T>::value, unsigned>::type
|
||||||
operator()(T) {
|
operator()(T) {
|
||||||
FMT_THROW(format_error("width is not integer"));
|
FMT_THROW(format_error("width is not integer"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char, typename Context>
|
template <typename Char, typename Context>
|
||||||
void printf(basic_buffer<Char> &buf, basic_string_view<Char> format,
|
void printf(basic_buffer<Char>& buf, basic_string_view<Char> format,
|
||||||
basic_format_args<Context> args) {
|
basic_format_args<Context> args) {
|
||||||
Context(std::back_inserter(buf), format, args).format();
|
Context(std::back_inserter(buf), format, args).format();
|
||||||
}
|
}
|
||||||
@ -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,17 +209,17 @@ 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:
|
||||||
typedef typename Range::value_type char_type;
|
typedef typename Range::value_type char_type;
|
||||||
typedef decltype(internal::declval<Range>().begin()) iterator;
|
typedef decltype(internal::declval<Range>().begin()) iterator;
|
||||||
typedef internal::arg_formatter_base<Range> base;
|
typedef internal::arg_formatter_base<Range> base;
|
||||||
typedef basic_printf_context<iterator, char_type> context_type;
|
typedef basic_printf_context<iterator, char_type> context_type;
|
||||||
|
|
||||||
context_type &context_;
|
context_type& context_;
|
||||||
|
|
||||||
void write_null_pointer(char) {
|
void write_null_pointer(char) {
|
||||||
this->spec()->type = 0;
|
this->spec()->type = 0;
|
||||||
@ -249,25 +241,24 @@ class printf_arg_formatter:
|
|||||||
specifier information for standard argument types.
|
specifier information for standard argument types.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
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>
|
||||||
typename std::enable_if<std::is_integral<T>::value, iterator>::type
|
typename std::enable_if<std::is_integral<T>::value, iterator>::type
|
||||||
operator()(T value) {
|
operator()(T value) {
|
||||||
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
||||||
// 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) {
|
||||||
format_specs &fmt_spec = *this->spec();
|
format_specs& fmt_spec = *this->spec();
|
||||||
if (fmt_spec.type && fmt_spec.type != 'c')
|
if (fmt_spec.type && fmt_spec.type != 'c')
|
||||||
return (*this)(static_cast<int>(value));
|
return (*this)(static_cast<int>(value));
|
||||||
fmt_spec.flags = 0;
|
fmt_spec.flags = 0;
|
||||||
@ -281,12 +272,12 @@ class printf_arg_formatter:
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<std::is_floating_point<T>::value, iterator>::type
|
typename std::enable_if<std::is_floating_point<T>::value, iterator>::type
|
||||||
operator()(T value) {
|
operator()(T value) {
|
||||||
return base::operator()(value);
|
return base::operator()(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Formats a null-terminated C string. */
|
/** Formats a null-terminated C string. */
|
||||||
iterator operator()(const char *value) {
|
iterator operator()(const char* value) {
|
||||||
if (value)
|
if (value)
|
||||||
base::operator()(value);
|
base::operator()(value);
|
||||||
else if (this->spec()->type == 'p')
|
else if (this->spec()->type == 'p')
|
||||||
@ -297,7 +288,7 @@ class printf_arg_formatter:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Formats a null-terminated wide C string. */
|
/** Formats a null-terminated wide C string. */
|
||||||
iterator operator()(const wchar_t *value) {
|
iterator operator()(const wchar_t* value) {
|
||||||
if (value)
|
if (value)
|
||||||
base::operator()(value);
|
base::operator()(value);
|
||||||
else if (this->spec()->type == 'p')
|
else if (this->spec()->type == 'p')
|
||||||
@ -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,13 +319,14 @@ 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()) {
|
||||||
internal::format_value(internal::get_container(ctx.out()), value);
|
internal::format_value(internal::get_container(ctx.out()), value);
|
||||||
return ctx.out();
|
return ctx.out();
|
||||||
}
|
}
|
||||||
@ -346,30 +335,31 @@ struct printf_formatter {
|
|||||||
/** This template formats data and writes the output to a writer. */
|
/** This template formats data and writes the output to a writer. */
|
||||||
template <typename OutputIt, typename Char, typename ArgFormatter>
|
template <typename OutputIt, typename Char, typename ArgFormatter>
|
||||||
class basic_printf_context :
|
class basic_printf_context :
|
||||||
// Inherit publicly as a workaround for the icc bug
|
// Inherit publicly as a workaround for the icc bug
|
||||||
// https://software.intel.com/en-us/forums/intel-c-compiler/topic/783476.
|
// https://software.intel.com/en-us/forums/intel-c-compiler/topic/783476.
|
||||||
public internal::context_base<
|
public internal::context_base<
|
||||||
OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> {
|
OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> {
|
||||||
public:
|
public:
|
||||||
/** 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;
|
||||||
typedef typename base::format_arg format_arg;
|
typedef typename base::format_arg format_arg;
|
||||||
typedef basic_format_specs<char_type> format_specs;
|
typedef basic_format_specs<char_type> format_specs;
|
||||||
|
|
||||||
static void parse_flags(format_specs &spec, const Char *&it, const Char *end);
|
static void parse_flags(format_specs& spec, const Char*& it, const Char* end);
|
||||||
|
|
||||||
// Returns the argument with specified index or, if arg_index is equal
|
// Returns the argument with specified index or, if arg_index is equal
|
||||||
// to the maximum unsigned value, the next argument.
|
// to the maximum unsigned value, the next argument.
|
||||||
format_arg get_arg(unsigned arg_index = std::numeric_limits<unsigned>::max());
|
format_arg get_arg(unsigned arg_index = std::numeric_limits<unsigned>::max());
|
||||||
|
|
||||||
// Parses argument index, flags and width and returns the argument index.
|
// Parses argument index, flags and width and returns the argument index.
|
||||||
unsigned parse_header(const Char *&it, const Char *end, format_specs &spec);
|
unsigned parse_header(const Char*& it, const Char* end, format_specs& spec);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@ -381,45 +371,46 @@ class basic_printf_context :
|
|||||||
*/
|
*/
|
||||||
basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
|
basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
|
||||||
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 '-':
|
||||||
spec.align_ = ALIGN_LEFT;
|
spec.align_ = ALIGN_LEFT;
|
||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
spec.flags |= SIGN_FLAG | PLUS_FLAG;
|
spec.flags |= SIGN_FLAG | PLUS_FLAG;
|
||||||
break;
|
break;
|
||||||
case '0':
|
case '0':
|
||||||
spec.fill_ = '0';
|
spec.fill_ = '0';
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
spec.flags |= SIGN_FLAG;
|
spec.flags |= SIGN_FLAG;
|
||||||
break;
|
break;
|
||||||
case '#':
|
case '#':
|
||||||
spec.flags |= HASH_FLAG;
|
spec.flags |= HASH_FLAG;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename Char, typename AF>
|
template <typename OutputIt, typename Char, typename AF>
|
||||||
typename basic_printf_context<OutputIt, Char, AF>::format_arg
|
typename basic_printf_context<OutputIt, Char, AF>::format_arg
|
||||||
basic_printf_context<OutputIt, Char, AF>::get_arg(unsigned arg_index) {
|
basic_printf_context<OutputIt, Char, AF>::get_arg(unsigned arg_index) {
|
||||||
if (arg_index == std::numeric_limits<unsigned>::max())
|
if (arg_index == std::numeric_limits<unsigned>::max())
|
||||||
return this->do_get_arg(this->parse_context().next_arg_id());
|
return this->do_get_arg(this->parse_context().next_arg_id());
|
||||||
return base::get_arg(arg_index - 1);
|
return base::get_arg(arg_index - 1);
|
||||||
@ -427,7 +418,7 @@ typename basic_printf_context<OutputIt, Char, AF>::format_arg
|
|||||||
|
|
||||||
template <typename OutputIt, typename Char, typename AF>
|
template <typename OutputIt, typename Char, typename AF>
|
||||||
unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
|
unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
|
||||||
const Char *&it, const Char *end, format_specs &spec) {
|
const Char*& it, const Char* end, format_specs& spec) {
|
||||||
unsigned arg_index = std::numeric_limits<unsigned>::max();
|
unsigned arg_index = std::numeric_limits<unsigned>::max();
|
||||||
char_type c = *it;
|
char_type c = *it;
|
||||||
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
||||||
@ -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.
|
||||||
@ -458,7 +448,7 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
|
|||||||
} else if (*it == '*') {
|
} else if (*it == '*') {
|
||||||
++it;
|
++it;
|
||||||
spec.width_ = visit_format_arg(
|
spec.width_ = visit_format_arg(
|
||||||
internal::printf_width_handler<char_type>(spec), get_arg());
|
internal::printf_width_handler<char_type>(spec), get_arg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return arg_index;
|
return arg_index;
|
||||||
@ -466,10 +456,10 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
|
|||||||
|
|
||||||
template <typename OutputIt, typename Char, typename AF>
|
template <typename OutputIt, typename Char, typename AF>
|
||||||
void basic_printf_context<OutputIt, Char, AF>::format() {
|
void basic_printf_context<OutputIt, Char, AF>::format() {
|
||||||
auto &buffer = internal::get_container(this->out());
|
auto& buffer = internal::get_container(this->out());
|
||||||
const auto range = this->parse_context();
|
const auto range = this->parse_context();
|
||||||
const Char * end = range.end();
|
const Char* end = range.end();
|
||||||
const Char * start = range.begin();
|
const Char* start = range.begin();
|
||||||
auto it = start;
|
auto it = start;
|
||||||
while (it != end) {
|
while (it != end) {
|
||||||
char_type c = *it++;
|
char_type c = *it++;
|
||||||
@ -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;
|
||||||
@ -595,28 +586,33 @@ typedef basic_format_args<wprintf_context> wprintf_args;
|
|||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Constructs an `~fmt::format_arg_store` object that contains references to
|
Constructs an `~fmt::format_arg_store` object that contains references to
|
||||||
arguments and can be implicitly converted to `~fmt::printf_args`.
|
arguments and can be implicitly converted to `~fmt::printf_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
|
||||||
Constructs an `~fmt::format_arg_store` object that contains references to
|
Constructs an `~fmt::format_arg_store` object that contains references to
|
||||||
arguments and can be implicitly converted to `~fmt::wprintf_args`.
|
arguments and can be implicitly converted to `~fmt::wprintf_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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -665,19 +663,20 @@ inline int vfprintf(std::FILE *f, const S &format,
|
|||||||
*/
|
*/
|
||||||
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::FILE *f, const S &format, const Args & ... args) {
|
fprintf(std::FILE* f, 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 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -692,20 +691,20 @@ inline int vprintf(const S &format,
|
|||||||
*/
|
*/
|
||||||
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)
|
||||||
printf(const S &format_str, const Args & ... args) {
|
printf(const S& format_str, 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;
|
||||||
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,12 +722,12 @@ 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;
|
||||||
format_arg_store<context, Args...> as{ args... };
|
format_arg_store<context, Args...> as{args...};
|
||||||
return vfprintf(os, to_string_view(format_str),
|
return vfprintf(os, to_string_view(format_str),
|
||||||
basic_format_args<context>(as));
|
basic_format_args<context>(as));
|
||||||
}
|
}
|
||||||
|
@ -12,20 +12,19 @@
|
|||||||
#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
|
||||||
# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
|
# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
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;
|
||||||
@ -55,87 +55,78 @@ struct formatting_tuple : formatting_base<Char> {
|
|||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template <typename RangeT, typename OutputIterator>
|
template <typename RangeT, typename OutputIterator>
|
||||||
void copy(const RangeT &range, OutputIterator out) {
|
void copy(const RangeT& range, OutputIterator out) {
|
||||||
for (auto it = range.begin(), end = range.end(); it != end; ++it)
|
for (auto it = range.begin(), end = range.end(); it != end; ++it)
|
||||||
*out++ = *it;
|
*out++ = *it;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIterator>
|
template <typename OutputIterator>
|
||||||
void copy(const char *str, OutputIterator out) {
|
void copy(const char* str, OutputIterator out) {
|
||||||
const char *p_curr = str;
|
const char* p_curr = str;
|
||||||
while (*p_curr) {
|
while (*p_curr) {
|
||||||
*out++ = *p_curr++;
|
*out++ = *p_curr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 =
|
||||||
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
|
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
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_<
|
||||||
false,
|
T, typename std::conditional<
|
||||||
conditional_helper<decltype(internal::declval<T>().begin()),
|
false,
|
||||||
decltype(internal::declval<T>().end())>,
|
conditional_helper<decltype(internal::declval<T>().begin()),
|
||||||
void>::type> : std::true_type {};
|
decltype(internal::declval<T>().end())>,
|
||||||
|
void>::type> : std::true_type {};
|
||||||
#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 =
|
||||||
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
|
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check for integer_sequence
|
// Check for integer_sequence
|
||||||
#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>
|
||||||
@ -151,7 +142,7 @@ using make_index_sequence = make_integer_sequence<std::size_t, N>;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class Tuple, class F, size_t... Is>
|
template <class Tuple, class F, size_t... Is>
|
||||||
void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT {
|
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT {
|
||||||
using std::get;
|
using std::get;
|
||||||
// using free function get<I>(T) now.
|
// using free function get<I>(T) now.
|
||||||
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
|
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
|
||||||
@ -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(
|
||||||
typename std::enable_if<
|
bool add_space, const Arg&,
|
||||||
!is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
|
typename std::enable_if<
|
||||||
|
!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(
|
||||||
typename std::enable_if<
|
bool add_space, const Arg&,
|
||||||
is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
|
typename std::enable_if<
|
||||||
|
is_like_std_string<typename std::decay<Arg>::type>::value>::type* =
|
||||||
|
nullptr) {
|
||||||
return add_space ? " \"{}\"" : "\"{}\"";
|
return add_space ? " \"{}\"" : "\"{}\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,33 +182,31 @@ FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) {
|
|||||||
return add_space ? " \"{}\"" : "\"{}\"";
|
return add_space ? " \"{}\"" : "\"{}\"";
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) {
|
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) {
|
||||||
return add_space ? L" \"{}\"" : L"\"{}\"";
|
return add_space ? L" \"{}\"" : L"\"{}\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
|
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
|
||||||
return add_space ? " '{}'" : "'{}'";
|
return add_space ? " '{}'" : "'{}'";
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
|
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
|
||||||
return add_space ? L" '{}'" : L"'{}'";
|
return add_space ? L" '{}'" : L"'{}'";
|
||||||
}
|
}
|
||||||
|
|
||||||
} // 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,19 +222,20 @@ 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:
|
||||||
formatting_tuple<Char> formatting;
|
formatting_tuple<Char> formatting;
|
||||||
|
|
||||||
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 formatting.parse(ctx);
|
return formatting.parse(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext = format_context>
|
template <typename FormatContext = format_context>
|
||||||
auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) {
|
auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||||
auto out = ctx.out();
|
auto out = ctx.out();
|
||||||
std::size_t i = 0;
|
std::size_t i = 0;
|
||||||
internal::copy(formatting.prefix, out);
|
internal::copy(formatting.prefix, out);
|
||||||
@ -255,26 +250,24 @@ 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
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>
|
||||||
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
return formatting.parse(ctx);
|
return formatting.parse(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@ -304,5 +297,4 @@ struct formatter<RangeT, Char,
|
|||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_RANGES_H_
|
#endif // FMT_RANGES_H_
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ FMT_BEGIN_NAMESPACE
|
|||||||
// Usage: f FMT_NOMACRO()
|
// Usage: f FMT_NOMACRO()
|
||||||
#define FMT_NOMACRO
|
#define FMT_NOMACRO
|
||||||
|
|
||||||
namespace internal{
|
namespace internal {
|
||||||
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
|
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
|
||||||
inline null<> localtime_s(...) { return null<>(); }
|
inline null<> localtime_s(...) { return null<>(); }
|
||||||
inline null<> gmtime_r(...) { return null<>(); }
|
inline null<> gmtime_r(...) { return null<>(); }
|
||||||
@ -31,14 +31,14 @@ inline std::tm localtime(std::time_t time) {
|
|||||||
std::time_t time_;
|
std::time_t time_;
|
||||||
std::tm tm_;
|
std::tm tm_;
|
||||||
|
|
||||||
dispatcher(std::time_t t): time_(t) {}
|
dispatcher(std::time_t t) : time_(t) {}
|
||||||
|
|
||||||
bool run() {
|
bool run() {
|
||||||
using namespace fmt::internal;
|
using namespace fmt::internal;
|
||||||
return handle(localtime_r(&time_, &tm_));
|
return handle(localtime_r(&time_, &tm_));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handle(std::tm *tm) { return tm != FMT_NULL; }
|
bool handle(std::tm* tm) { return tm != FMT_NULL; }
|
||||||
|
|
||||||
bool handle(internal::null<>) {
|
bool handle(internal::null<>) {
|
||||||
using namespace fmt::internal;
|
using namespace fmt::internal;
|
||||||
@ -50,7 +50,7 @@ inline std::tm localtime(std::time_t time) {
|
|||||||
#if !FMT_MSC_VER
|
#if !FMT_MSC_VER
|
||||||
bool fallback(internal::null<>) {
|
bool fallback(internal::null<>) {
|
||||||
using namespace fmt::internal;
|
using namespace fmt::internal;
|
||||||
std::tm *tm = std::localtime(&time_);
|
std::tm* tm = std::localtime(&time_);
|
||||||
if (tm) tm_ = *tm;
|
if (tm) tm_ = *tm;
|
||||||
return tm != FMT_NULL;
|
return tm != FMT_NULL;
|
||||||
}
|
}
|
||||||
@ -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_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,14 +68,14 @@ inline std::tm gmtime(std::time_t time) {
|
|||||||
std::time_t time_;
|
std::time_t time_;
|
||||||
std::tm tm_;
|
std::tm tm_;
|
||||||
|
|
||||||
dispatcher(std::time_t t): time_(t) {}
|
dispatcher(std::time_t t) : time_(t) {}
|
||||||
|
|
||||||
bool run() {
|
bool run() {
|
||||||
using namespace fmt::internal;
|
using namespace fmt::internal;
|
||||||
return handle(gmtime_r(&time_, &tm_));
|
return handle(gmtime_r(&time_, &tm_));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handle(std::tm *tm) { return tm != FMT_NULL; }
|
bool handle(std::tm* tm) { return tm != FMT_NULL; }
|
||||||
|
|
||||||
bool handle(internal::null<>) {
|
bool handle(internal::null<>) {
|
||||||
using namespace fmt::internal;
|
using namespace fmt::internal;
|
||||||
@ -87,7 +86,7 @@ inline std::tm gmtime(std::time_t time) {
|
|||||||
|
|
||||||
#if !FMT_MSC_VER
|
#if !FMT_MSC_VER
|
||||||
bool fallback(internal::null<>) {
|
bool fallback(internal::null<>) {
|
||||||
std::tm *tm = std::gmtime(&time_);
|
std::tm* tm = std::gmtime(&time_);
|
||||||
if (tm) tm_ = *tm;
|
if (tm) tm_ = *tm;
|
||||||
return tm != FMT_NULL;
|
return tm != FMT_NULL;
|
||||||
}
|
}
|
||||||
@ -95,33 +94,29 @@ 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_;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
inline std::size_t strftime(char *str, std::size_t count, const char *format,
|
inline std::size_t strftime(char* str, std::size_t count, const char* format,
|
||||||
const std::tm *time) {
|
const std::tm* time) {
|
||||||
return std::strftime(str, count, format, time);
|
return std::strftime(str, count, format, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::size_t strftime(wchar_t *str, std::size_t count,
|
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');
|
||||||
@ -129,13 +124,13 @@ struct formatter<std::tm, Char> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
|
auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||||
basic_memory_buffer<Char> buf;
|
basic_memory_buffer<Char> buf;
|
||||||
std::size_t start = buf.size();
|
std::size_t start = buf.size();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
std::size_t size = buf.capacity() - start;
|
std::size_t size = buf.capacity() - start;
|
||||||
std::size_t count =
|
std::size_t count =
|
||||||
internal::strftime(&buf[start], size, &tm_format[0], &tm);
|
internal::strftime(&buf[start], size, &tm_format[0], &tm);
|
||||||
if (count != 0) {
|
if (count != 0) {
|
||||||
buf.resize(start + count);
|
buf.resize(start + count);
|
||||||
break;
|
break;
|
||||||
|
@ -9,50 +9,55 @@
|
|||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
template struct internal::basic_data<void>;
|
template struct internal::basic_data<void>;
|
||||||
template FMT_API internal::locale_ref::locale_ref(const std::locale &loc);
|
template FMT_API internal::locale_ref::locale_ref(const std::locale& loc);
|
||||||
template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
|
template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
|
||||||
|
|
||||||
// Explicit instantiations for char.
|
// Explicit instantiations for char.
|
||||||
|
|
||||||
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>);
|
||||||
|
|
||||||
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>&);
|
||||||
|
|
||||||
template FMT_API int internal::char_traits<wchar_t>::format_float(
|
template FMT_API int internal::char_traits<wchar_t>::format_float(
|
||||||
wchar_t *, std::size_t, const wchar_t *, int, double);
|
wchar_t*, std::size_t, const wchar_t*, int, double);
|
||||||
|
|
||||||
template FMT_API int internal::char_traits<wchar_t>::format_float(
|
template FMT_API int internal::char_traits<wchar_t>::format_float(
|
||||||
wchar_t *, std::size_t, const wchar_t *, int, long double);
|
wchar_t*, std::size_t, const wchar_t*, int, long double);
|
||||||
|
|
||||||
template FMT_API std::wstring internal::vformat<wchar_t>(
|
template FMT_API std::wstring internal::vformat<wchar_t>(
|
||||||
wstring_view, basic_format_args<wformat_context>);
|
wstring_view, basic_format_args<wformat_context>);
|
||||||
|
99
src/posix.cc
99
src/posix.cc
@ -7,43 +7,43 @@
|
|||||||
|
|
||||||
// Disable bogus MSVC warnings.
|
// Disable bogus MSVC warnings.
|
||||||
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
|
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
|
||||||
# define _CRT_SECURE_NO_WARNINGS
|
# define _CRT_SECURE_NO_WARNINGS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#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>
|
||||||
#else
|
#else
|
||||||
# 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
|
||||||
|
|
||||||
# ifndef S_IRUSR
|
# ifndef S_IRUSR
|
||||||
# define S_IRUSR _S_IREAD
|
# define S_IRUSR _S_IREAD
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifndef S_IWUSR
|
# ifndef S_IWUSR
|
||||||
# define S_IWUSR _S_IWRITE
|
# define S_IWUSR _S_IWRITE
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef __MINGW32__
|
# ifdef __MINGW32__
|
||||||
# define _SH_DENYNO 0x40
|
# define _SH_DENYNO 0x40
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
#ifdef fileno
|
#ifdef fileno
|
||||||
# undef fileno
|
# undef fileno
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -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 {
|
||||||
@ -148,24 +143,22 @@ long long file::size() const {
|
|||||||
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
|
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
|
||||||
FMT_THROW(system_error(errno, "cannot get file attributes"));
|
FMT_THROW(system_error(errno, "cannot get file attributes"));
|
||||||
static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
|
static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
|
||||||
"return type of file::size is not large enough");
|
"return type of file::size is not large enough");
|
||||||
return file_stat.st_size;
|
return file_stat.st_size;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
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,19 +175,18 @@ 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) {
|
||||||
// Close the descriptors first to make sure that assignments don't throw
|
// Close the descriptors first to make sure that assignments don't throw
|
||||||
// and there are no leaks.
|
// and there are no leaks.
|
||||||
read_end.close();
|
read_end.close();
|
||||||
@ -209,20 +201,19 @@ 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]);
|
||||||
write_end = file(fds[1]);
|
write_end = file(fds[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffered_file file::fdopen(const char *mode) {
|
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
|
||||||
|
|
||||||
|
@ -9,14 +9,14 @@
|
|||||||
#include "gtest.h"
|
#include "gtest.h"
|
||||||
|
|
||||||
#if GTEST_HAS_DEATH_TEST
|
#if GTEST_HAS_DEATH_TEST
|
||||||
# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \
|
# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \
|
||||||
EXPECT_DEBUG_DEATH(statement, regex)
|
EXPECT_DEBUG_DEATH(statement, regex)
|
||||||
#else
|
#else
|
||||||
# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \
|
# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \
|
||||||
GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
|
GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
|
||||||
#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!");
|
||||||
}
|
}
|
||||||
|
@ -34,18 +34,19 @@ std::tm make_second(int s) {
|
|||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string format_tm(const std::tm &time, const char *spec,
|
std::string format_tm(const std::tm& time, const char* spec,
|
||||||
const std::locale &loc) {
|
const std::locale& loc) {
|
||||||
auto &facet = std::use_facet<std::time_put<char>>(loc);
|
auto& facet = std::use_facet<std::time_put<char>>(loc);
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os.imbue(loc);
|
os.imbue(loc);
|
||||||
facet.put(os, os, ' ', &time, spec, spec + std::strlen(spec));
|
facet.put(os, os, ' ', &time, spec, spec + std::strlen(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"); \
|
{ \
|
||||||
EXPECT_EQ(format_tm(time, spec, loc), \
|
std::locale loc("ja_JP.utf8"); \
|
||||||
|
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) {
|
||||||
@ -162,13 +162,14 @@ TEST(ChronoTest, InvalidSpecs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ChronoTest, Locale) {
|
TEST(ChronoTest, Locale) {
|
||||||
const char *loc_name = "ja_JP.utf8";
|
const char* loc_name = "ja_JP.utf8";
|
||||||
bool has_locale = false;
|
bool has_locale = false;
|
||||||
std::locale loc;
|
std::locale loc;
|
||||||
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;
|
||||||
|
@ -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"
|
||||||
|
|
||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
// Check if fmt/core.h compiles with windows.h included before it.
|
// Check if fmt/core.h compiles with windows.h included before it.
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "fmt/core.h"
|
#include "fmt/core.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;
|
||||||
@ -42,24 +42,23 @@ namespace {
|
|||||||
struct test_struct {};
|
struct test_struct {};
|
||||||
|
|
||||||
template <typename Context, typename T>
|
template <typename Context, typename T>
|
||||||
basic_format_arg<Context> make_arg(const T &value) {
|
basic_format_arg<Context> make_arg(const T& value) {
|
||||||
return fmt::internal::make_arg<Context>(value);
|
return fmt::internal::make_arg<Context>(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();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::back_insert_iterator<basic_buffer<Char>> iterator;
|
typedef std::back_insert_iterator<basic_buffer<Char>> iterator;
|
||||||
|
|
||||||
auto format(test_struct, basic_format_context<iterator, char> &ctx)
|
auto format(test_struct, basic_format_context<iterator, char>& ctx)
|
||||||
-> decltype(ctx.out()) {
|
-> decltype(ctx.out()) {
|
||||||
const Char *test = "test";
|
const Char* test = "test";
|
||||||
return std::copy_n(test, std::strlen(test), ctx.out());
|
return std::copy_n(test, std::strlen(test), ctx.out());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -67,31 +66,29 @@ FMT_END_NAMESPACE
|
|||||||
|
|
||||||
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
|
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
|
||||||
TEST(BufferTest, Noncopyable) {
|
TEST(BufferTest, Noncopyable) {
|
||||||
EXPECT_FALSE(std::is_copy_constructible<basic_buffer<char> >::value);
|
EXPECT_FALSE(std::is_copy_constructible<basic_buffer<char>>::value);
|
||||||
#if !FMT_MSC_VER
|
# if !FMT_MSC_VER
|
||||||
// std::is_copy_assignable is broken in MSVC2013.
|
// std::is_copy_assignable is broken in MSVC2013.
|
||||||
EXPECT_FALSE(std::is_copy_assignable<basic_buffer<char> >::value);
|
EXPECT_FALSE(std::is_copy_assignable<basic_buffer<char>>::value);
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BufferTest, Nonmoveable) {
|
TEST(BufferTest, Nonmoveable) {
|
||||||
EXPECT_FALSE(std::is_move_constructible<basic_buffer<char> >::value);
|
EXPECT_FALSE(std::is_move_constructible<basic_buffer<char>>::value);
|
||||||
#if !FMT_MSC_VER
|
# if !FMT_MSC_VER
|
||||||
// std::is_move_assignable is broken in MSVC2013.
|
// std::is_move_assignable is broken in MSVC2013.
|
||||||
EXPECT_FALSE(std::is_move_assignable<basic_buffer<char> >::value);
|
EXPECT_FALSE(std::is_move_assignable<basic_buffer<char>>::value);
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
#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) {
|
||||||
this->set(this->data(), capacity);
|
this->set(this->data(), capacity);
|
||||||
@ -99,8 +96,8 @@ struct mock_buffer : basic_buffer<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mock_buffer() {}
|
mock_buffer() {}
|
||||||
mock_buffer(T *data) { this->set(data, 0); }
|
mock_buffer(T* data) { this->set(data, 0); }
|
||||||
mock_buffer(T *data, std::size_t capacity) { this->set(data, capacity); }
|
mock_buffer(T* data, std::size_t capacity) { this->set(data, capacity); }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(BufferTest, Ctor) {
|
TEST(BufferTest, Ctor) {
|
||||||
@ -134,9 +131,9 @@ struct dying_buffer : test_buffer<int> {
|
|||||||
|
|
||||||
TEST(BufferTest, VirtualDtor) {
|
TEST(BufferTest, VirtualDtor) {
|
||||||
typedef StrictMock<dying_buffer> stict_mock_buffer;
|
typedef StrictMock<dying_buffer> stict_mock_buffer;
|
||||||
stict_mock_buffer *mock_buffer = new stict_mock_buffer();
|
stict_mock_buffer* mock_buffer = new stict_mock_buffer();
|
||||||
EXPECT_CALL(*mock_buffer, die());
|
EXPECT_CALL(*mock_buffer, die());
|
||||||
basic_buffer<int> *buffer = mock_buffer;
|
basic_buffer<int>* buffer = mock_buffer;
|
||||||
delete buffer;
|
delete buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +144,7 @@ TEST(BufferTest, Access) {
|
|||||||
EXPECT_EQ(11, buffer[0]);
|
EXPECT_EQ(11, buffer[0]);
|
||||||
buffer[3] = 42;
|
buffer[3] = 42;
|
||||||
EXPECT_EQ(42, *(&buffer[0] + 3));
|
EXPECT_EQ(42, *(&buffer[0] + 3));
|
||||||
const basic_buffer<char> &const_buffer = buffer;
|
const basic_buffer<char>& const_buffer = buffer;
|
||||||
EXPECT_EQ(42, const_buffer[3]);
|
EXPECT_EQ(42, const_buffer[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +179,7 @@ TEST(BufferTest, Clear) {
|
|||||||
TEST(BufferTest, Append) {
|
TEST(BufferTest, Append) {
|
||||||
char data[15];
|
char data[15];
|
||||||
mock_buffer<char> buffer(data, 10);
|
mock_buffer<char> buffer(data, 10);
|
||||||
const char *test = "test";
|
const char* test = "test";
|
||||||
buffer.append(test, test + 5);
|
buffer.append(test, test + 5);
|
||||||
EXPECT_STREQ(test, &buffer[0]);
|
EXPECT_STREQ(test, &buffer[0]);
|
||||||
EXPECT_EQ(5u, buffer.size());
|
EXPECT_EQ(5u, buffer.size());
|
||||||
@ -197,7 +194,7 @@ TEST(BufferTest, Append) {
|
|||||||
TEST(BufferTest, AppendAllocatesEnoughStorage) {
|
TEST(BufferTest, AppendAllocatesEnoughStorage) {
|
||||||
char data[19];
|
char data[19];
|
||||||
mock_buffer<char> buffer(data, 10);
|
mock_buffer<char> buffer(data, 10);
|
||||||
const char *test = "abcdefgh";
|
const char* test = "abcdefgh";
|
||||||
buffer.resize(10);
|
buffer.resize(10);
|
||||||
EXPECT_CALL(buffer, do_grow(19));
|
EXPECT_CALL(buffer, do_grow(19));
|
||||||
buffer.append(test, test + 9);
|
buffer.append(test, test + 9);
|
||||||
@ -211,15 +208,14 @@ 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()) {
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *format(const T &, custom_context& ctx) {
|
const char* format(const T&, custom_context& ctx) {
|
||||||
ctx.called = true;
|
ctx.called = true;
|
||||||
return FMT_NULL;
|
return FMT_NULL;
|
||||||
}
|
}
|
||||||
@ -231,7 +227,7 @@ struct custom_context {
|
|||||||
fmt::format_parse_context parse_context() {
|
fmt::format_parse_context parse_context() {
|
||||||
return fmt::format_parse_context("");
|
return fmt::format_parse_context("");
|
||||||
}
|
}
|
||||||
void advance_to(const char *) {}
|
void advance_to(const char*) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(ArgTest, MakeValueWithCustomContext) {
|
TEST(ArgTest, MakeValueWithCustomContext) {
|
||||||
@ -249,40 +245,35 @@ 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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
MOCK_METHOD1_T(visit, test_result (T value));
|
MOCK_METHOD1_T(visit, test_result(T value));
|
||||||
MOCK_METHOD0_T(unexpected, void ());
|
MOCK_METHOD0_T(unexpected, void());
|
||||||
|
|
||||||
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,28 +290,30 @@ 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; \
|
{ \
|
||||||
EXPECT_CALL(visitor, visit(expected)); \
|
testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
|
||||||
typedef std::back_insert_iterator<basic_buffer<Char>> iterator; \
|
EXPECT_CALL(visitor, visit(expected)); \
|
||||||
fmt::visit(visitor, \
|
typedef std::back_insert_iterator<basic_buffer<Char>> iterator; \
|
||||||
make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
|
fmt::visit(visitor, \
|
||||||
}
|
make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
|
||||||
|
}
|
||||||
|
|
||||||
#define CHECK_ARG(value, typename_) { \
|
#define CHECK_ARG(value, typename_) \
|
||||||
typedef decltype(value) value_type; \
|
{ \
|
||||||
typename_ visit_type<value_type>::Type expected = value; \
|
typedef decltype(value) value_type; \
|
||||||
CHECK_ARG_(char, expected, value) \
|
typename_ visit_type<value_type>::Type expected = value; \
|
||||||
CHECK_ARG_(wchar_t, expected, value) \
|
CHECK_ARG_(char, 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>
|
||||||
@ -330,7 +323,7 @@ typename std::enable_if<std::is_integral<T>::value, T>::type test_value() {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
||||||
test_value() {
|
test_value() {
|
||||||
return static_cast<T>(4.2);
|
return static_cast<T>(4.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,8 +341,8 @@ TEST(ArgTest, CharArg) {
|
|||||||
|
|
||||||
TEST(ArgTest, StringArg) {
|
TEST(ArgTest, StringArg) {
|
||||||
char str_data[] = "test";
|
char str_data[] = "test";
|
||||||
char *str = str_data;
|
char* str = str_data;
|
||||||
const char *cstr = str;
|
const char* cstr = str;
|
||||||
CHECK_ARG_(char, cstr, str);
|
CHECK_ARG_(char, cstr, str);
|
||||||
|
|
||||||
string_view sref(str);
|
string_view sref(str);
|
||||||
@ -358,8 +351,8 @@ TEST(ArgTest, StringArg) {
|
|||||||
|
|
||||||
TEST(ArgTest, WStringArg) {
|
TEST(ArgTest, WStringArg) {
|
||||||
wchar_t str_data[] = L"test";
|
wchar_t str_data[] = L"test";
|
||||||
wchar_t *str = str_data;
|
wchar_t* str = str_data;
|
||||||
const wchar_t *cstr = str;
|
const wchar_t* cstr = str;
|
||||||
|
|
||||||
fmt::wstring_view sref(str);
|
fmt::wstring_view sref(str);
|
||||||
CHECK_ARG_(wchar_t, cstr, str);
|
CHECK_ARG_(wchar_t, cstr, str);
|
||||||
@ -369,8 +362,8 @@ TEST(ArgTest, WStringArg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArgTest, PointerArg) {
|
TEST(ArgTest, PointerArg) {
|
||||||
void *p = FMT_NULL;
|
void* p = FMT_NULL;
|
||||||
const void *cp = FMT_NULL;
|
const void* cp = FMT_NULL;
|
||||||
CHECK_ARG_(char, cp, p);
|
CHECK_ARG_(char, cp, p);
|
||||||
CHECK_ARG_(wchar_t, cp, p);
|
CHECK_ARG_(wchar_t, cp, p);
|
||||||
CHECK_ARG(cp, );
|
CHECK_ARG(cp, );
|
||||||
@ -384,7 +377,7 @@ struct check_custom {
|
|||||||
test_buffer() : fmt::internal::basic_buffer<char>(data, 0, 10) {}
|
test_buffer() : fmt::internal::basic_buffer<char>(data, 0, 10) {}
|
||||||
void grow(std::size_t) {}
|
void grow(std::size_t) {}
|
||||||
} buffer;
|
} buffer;
|
||||||
fmt::internal::basic_buffer<char> &base = buffer;
|
fmt::internal::basic_buffer<char>& base = buffer;
|
||||||
fmt::format_context ctx(std::back_inserter(base), "", fmt::format_args());
|
fmt::format_context ctx(std::back_inserter(base), "", fmt::format_args());
|
||||||
h.format(ctx);
|
h.format(ctx);
|
||||||
EXPECT_EQ("test", std::string(buffer.data, buffer.size()));
|
EXPECT_EQ("test", std::string(buffer.data, buffer.size()));
|
||||||
@ -395,14 +388,14 @@ struct check_custom {
|
|||||||
TEST(ArgTest, CustomArg) {
|
TEST(ArgTest, CustomArg) {
|
||||||
test_struct test;
|
test_struct test;
|
||||||
typedef mock_visitor<fmt::basic_format_arg<fmt::format_context>::handle>
|
typedef mock_visitor<fmt::basic_format_arg<fmt::format_context>::handle>
|
||||||
visitor;
|
visitor;
|
||||||
testing::StrictMock<visitor> v;
|
testing::StrictMock<visitor> v;
|
||||||
EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke(check_custom()));
|
EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke(check_custom()));
|
||||||
fmt::visit(v, make_arg<fmt::format_context>(test));
|
fmt::visit(v, make_arg<fmt::format_context>(test));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArgTest, VisitInvalidArg) {
|
TEST(ArgTest, VisitInvalidArg) {
|
||||||
testing::StrictMock< mock_visitor<fmt::monostate> > visitor;
|
testing::StrictMock<mock_visitor<fmt::monostate>> visitor;
|
||||||
EXPECT_CALL(visitor, visit(_));
|
EXPECT_CALL(visitor, visit(_));
|
||||||
fmt::basic_format_arg<fmt::format_context> arg;
|
fmt::basic_format_arg<fmt::format_context> arg;
|
||||||
visit(visitor, arg);
|
visit(visitor, arg);
|
||||||
@ -416,9 +409,8 @@ 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) {
|
||||||
for (std::size_t j = 0; j < num_inputs; ++j) {
|
for (std::size_t j = 0; j < num_inputs; ++j) {
|
||||||
@ -446,7 +438,7 @@ enum basic_enum {};
|
|||||||
|
|
||||||
TEST(CoreTest, ConvertToInt) {
|
TEST(CoreTest, ConvertToInt) {
|
||||||
EXPECT_FALSE((fmt::convert_to_int<char, char>::value));
|
EXPECT_FALSE((fmt::convert_to_int<char, char>::value));
|
||||||
EXPECT_FALSE((fmt::convert_to_int<const char *, char>::value));
|
EXPECT_FALSE((fmt::convert_to_int<const char*, char>::value));
|
||||||
EXPECT_TRUE((fmt::convert_to_int<basic_enum, char>::value));
|
EXPECT_TRUE((fmt::convert_to_int<basic_enum, char>::value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,31 +449,31 @@ 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 {
|
||||||
public:
|
public:
|
||||||
QString(const wchar_t *s) : s_(std::make_shared<std::wstring>(s)) {}
|
QString(const wchar_t* s) : s_(std::make_shared<std::wstring>(s)) {}
|
||||||
const wchar_t *utf16() const FMT_NOEXCEPT { return s_->data(); }
|
const wchar_t* utf16() const FMT_NOEXCEPT { return s_->data(); }
|
||||||
int size() const FMT_NOEXCEPT { return static_cast<int>(s_->size()); }
|
int size() const FMT_NOEXCEPT { return static_cast<int>(s_->size()); }
|
||||||
#ifdef FMT_STRING_VIEW
|
#ifdef FMT_STRING_VIEW
|
||||||
operator FMT_STRING_VIEW<wchar_t>() const FMT_NOEXCEPT { return *s_; }
|
operator FMT_STRING_VIEW<wchar_t>() const FMT_NOEXCEPT { return *s_; }
|
||||||
@ -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,18 +496,18 @@ 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));
|
||||||
EXPECT_TRUE((fmt::internal::is_string<const TypeParam *>::value));
|
EXPECT_TRUE((fmt::internal::is_string<const TypeParam*>::value));
|
||||||
EXPECT_TRUE((fmt::internal::is_string<TypeParam[2]>::value));
|
EXPECT_TRUE((fmt::internal::is_string<TypeParam[2]>::value));
|
||||||
EXPECT_TRUE((fmt::internal::is_string<const TypeParam[2]>::value));
|
EXPECT_TRUE((fmt::internal::is_string<const TypeParam[2]>::value));
|
||||||
EXPECT_TRUE((fmt::internal::is_string<std::basic_string<TypeParam>>::value));
|
EXPECT_TRUE((fmt::internal::is_string<std::basic_string<TypeParam>>::value));
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
(fmt::internal::is_string<fmt::basic_string_view<TypeParam>>::value));
|
(fmt::internal::is_string<fmt::basic_string_view<TypeParam>>::value));
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
(fmt::internal::is_string<derived_from_string_view<TypeParam>>::value));
|
(fmt::internal::is_string<derived_from_string_view<TypeParam>>::value));
|
||||||
#ifdef FMT_STRING_VIEW
|
#ifdef FMT_STRING_VIEW
|
||||||
EXPECT_TRUE((fmt::internal::is_string<FMT_STRING_VIEW<TypeParam>>::value));
|
EXPECT_TRUE((fmt::internal::is_string<FMT_STRING_VIEW<TypeParam>>::value));
|
||||||
#endif
|
#endif
|
||||||
@ -529,7 +519,7 @@ TYPED_TEST(IsStringTest, IsString) {
|
|||||||
TEST(CoreTest, Format) {
|
TEST(CoreTest, Format) {
|
||||||
// This should work without including fmt/format.h.
|
// This should work without including fmt/format.h.
|
||||||
#ifdef FMT_FORMAT_H_
|
#ifdef FMT_FORMAT_H_
|
||||||
# error fmt/format.h must not be included in the core test
|
# error fmt/format.h must not be included in the core test
|
||||||
#endif
|
#endif
|
||||||
EXPECT_EQ(fmt::format("{}", 42), "42");
|
EXPECT_EQ(fmt::format("{}", 42), "42");
|
||||||
}
|
}
|
||||||
@ -537,7 +527,7 @@ TEST(CoreTest, Format) {
|
|||||||
TEST(CoreTest, FormatTo) {
|
TEST(CoreTest, FormatTo) {
|
||||||
// This should work without including fmt/format.h.
|
// This should work without including fmt/format.h.
|
||||||
#ifdef FMT_FORMAT_H_
|
#ifdef FMT_FORMAT_H_
|
||||||
# error fmt/format.h must not be included in the core test
|
# error fmt/format.h must not be included in the core test
|
||||||
#endif
|
#endif
|
||||||
std::string s;
|
std::string s;
|
||||||
fmt::format_to(std::back_inserter(s), "{}", 42);
|
fmt::format_to(std::back_inserter(s), "{}", 42);
|
||||||
@ -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) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -41,7 +40,7 @@ std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
std::string custom_format(const char *format_str, const Args & ... args) {
|
std::string custom_format(const char* format_str, const Args&... args) {
|
||||||
auto va = fmt::make_format_args(args...);
|
auto va = fmt::make_format_args(args...);
|
||||||
return custom_vformat(format_str, va);
|
return custom_vformat(format_str, va);
|
||||||
}
|
}
|
||||||
|
@ -25,20 +25,18 @@
|
|||||||
#undef max
|
#undef max
|
||||||
|
|
||||||
#if FMT_HAS_CPP_ATTRIBUTE(noreturn)
|
#if FMT_HAS_CPP_ATTRIBUTE(noreturn)
|
||||||
# define FMT_NORETURN [[noreturn]]
|
# define FMT_NORETURN [[noreturn]]
|
||||||
#else
|
#else
|
||||||
# define FMT_NORETURN
|
# define FMT_NORETURN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
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()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -136,7 +130,7 @@ TEST(FormatTest, FormatNegativeNaN) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, StrError) {
|
TEST(FormatTest, StrError) {
|
||||||
char *message = FMT_NULL;
|
char* message = FMT_NULL;
|
||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = FMT_NULL, 0),
|
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = FMT_NULL, 0),
|
||||||
"invalid buffer");
|
"invalid buffer");
|
||||||
@ -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;
|
||||||
@ -231,7 +224,7 @@ TEST(ColorsTest, ColorsPrint) {
|
|||||||
EXPECT_WRITE(stderr, fmt::print(stderr, fmt::emphasis::bold, "bold error"),
|
EXPECT_WRITE(stderr, fmt::print(stderr, fmt::emphasis::bold, "bold error"),
|
||||||
"\x1b[1mbold error\x1b[0m");
|
"\x1b[1mbold error\x1b[0m");
|
||||||
EXPECT_WRITE(stderr, fmt::print(stderr, fg(fmt::color::blue), "blue log"),
|
EXPECT_WRITE(stderr, fmt::print(stderr, fg(fmt::color::blue), "blue log"),
|
||||||
"\x1b[38;2;000;000;255mblue log\x1b[0m");
|
"\x1b[38;2;000;000;255mblue log\x1b[0m");
|
||||||
EXPECT_WRITE(stdout, fmt::print(fmt::text_style(), "hi"), "hi");
|
EXPECT_WRITE(stdout, fmt::print(fmt::text_style(), "hi"), "hi");
|
||||||
EXPECT_WRITE(stdout, fmt::print(fg(fmt::terminal_color::red), "tred"),
|
EXPECT_WRITE(stdout, fmt::print(fg(fmt::terminal_color::red), "tred"),
|
||||||
"\x1b[31mtred\x1b[0m");
|
"\x1b[31mtred\x1b[0m");
|
||||||
@ -250,18 +243,19 @@ 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(
|
||||||
"\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m");
|
fmt::format(fg(fmt::color::blue) | bg(fmt::color::red), "two color"),
|
||||||
EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold"),
|
"\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m");
|
||||||
"\x1b[1mbold\x1b[0m");
|
EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold"), "\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(
|
||||||
"\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m");
|
fmt::format(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"),
|
||||||
|
"\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");
|
||||||
EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue log"),
|
EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue log"),
|
||||||
|
1015
test/format-test.cc
1015
test/format-test.cc
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -7,22 +7,22 @@
|
|||||||
|
|
||||||
#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
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// This is used to suppress coverity warnings about untrusted values.
|
// This is used to suppress coverity warnings about untrusted values.
|
||||||
std::string sanitize(const std::string &s) {
|
std::string sanitize(const std::string& s) {
|
||||||
std::string result;
|
std::string result;
|
||||||
for (std::string::const_iterator i = s.begin(), end = s.end(); i != end; ++i)
|
for (std::string::const_iterator i = s.begin(), end = s.end(); i != end; ++i)
|
||||||
result.push_back(static_cast<char>(*i & 0xff));
|
result.push_back(static_cast<char>(*i & 0xff));
|
||||||
@ -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,43 +67,50 @@ 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(
|
||||||
a_++;
|
{ // NOLINT
|
||||||
throw_exception();
|
a_++;
|
||||||
}, std::exception, (b_++, "test"));
|
throw_exception();
|
||||||
|
},
|
||||||
|
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(
|
||||||
a_++;
|
{ // NOLINT
|
||||||
throw_exception();
|
a_++;
|
||||||
}, std::logic_error, (b_++, "test")), "throws a different type");
|
throw_exception();
|
||||||
|
},
|
||||||
|
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(
|
||||||
a_++;
|
{ // NOLINT
|
||||||
throw_exception();
|
a_++;
|
||||||
}, std::exception, (b_++, "other")),
|
throw_exception();
|
||||||
"throws an exception with a different message");
|
},
|
||||||
|
std::exception, (b_++, "other")),
|
||||||
|
"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(
|
||||||
a_++;
|
{ // NOLINT
|
||||||
throw_system_error();
|
a_++;
|
||||||
}, EDOM, (b_++, "test"));
|
throw_system_error();
|
||||||
|
},
|
||||||
|
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(
|
||||||
a_++;
|
{ // NOLINT
|
||||||
throw_exception();
|
a_++;
|
||||||
}, EDOM, (b_++, "test")), "throws a different type");
|
throw_exception();
|
||||||
|
},
|
||||||
|
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(
|
||||||
a_++;
|
{ // NOLINT
|
||||||
throw_system_error();
|
a_++;
|
||||||
}, EDOM, (b_++, "other")),
|
throw_system_error();
|
||||||
"throws an exception with a different message");
|
},
|
||||||
|
EDOM, (b_++, "other")),
|
||||||
|
"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,
|
||||||
a_++;
|
{ // NOLINT
|
||||||
std::printf("test");
|
a_++;
|
||||||
}, (b_++, "test"));
|
std::printf("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,
|
||||||
a_++;
|
{ // NOLINT
|
||||||
std::printf("test");
|
a_++;
|
||||||
}, (b_++, "other")), "Actual: test");
|
std::printf("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,10 +283,9 @@ 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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(StreamingAssertionsTest, EXPECT_THROW_MSG) {
|
TEST(StreamingAssertionsTest, EXPECT_THROW_MSG) {
|
||||||
@ -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,15 +413,17 @@ 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
|
||||||
FMT_POSIX(close(write_fd));
|
// will break output redirection.
|
||||||
SUPPRESS_ASSERT(redir.reset(FMT_NULL));
|
FMT_POSIX(close(write_fd));
|
||||||
}, format_system_error(EBADF, "cannot flush stream"));
|
SUPPRESS_ASSERT(redir.reset(FMT_NULL));
|
||||||
write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail
|
},
|
||||||
|
format_system_error(EBADF, "cannot flush stream"));
|
||||||
|
write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FMT_USE_FILE_DESCRIPTORS
|
#endif // FMT_USE_FILE_DESCRIPTORS
|
||||||
|
@ -12,25 +12,23 @@
|
|||||||
using fmt::file;
|
using fmt::file;
|
||||||
|
|
||||||
void OutputRedirect::flush() {
|
void OutputRedirect::flush() {
|
||||||
#if EOF != -1
|
# if EOF != -1
|
||||||
# error "FMT_RETRY assumes return value of -1 indicating failure"
|
# error "FMT_RETRY assumes return value of -1 indicating failure"
|
||||||
#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_)));
|
||||||
original_.close();
|
original_.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputRedirect::OutputRedirect(FILE *f) : file_(f) {
|
OutputRedirect::OutputRedirect(FILE* f) : file_(f) {
|
||||||
flush();
|
flush();
|
||||||
int fd = FMT_POSIX(fileno(f));
|
int fd = FMT_POSIX(fileno(f));
|
||||||
// Create a file object referring to the original file.
|
// Create a file object referring to the original file.
|
||||||
@ -45,7 +43,7 @@ OutputRedirect::OutputRedirect(FILE *f) : file_(f) {
|
|||||||
OutputRedirect::~OutputRedirect() FMT_NOEXCEPT {
|
OutputRedirect::~OutputRedirect() FMT_NOEXCEPT {
|
||||||
try {
|
try {
|
||||||
restore();
|
restore();
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception& e) {
|
||||||
std::fputs(e.what(), stderr);
|
std::fputs(e.what(), stderr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
@ -69,7 +66,7 @@ std::string OutputRedirect::restore_and_read() {
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string read(file &f, std::size_t count) {
|
std::string read(file& f, std::size_t count) {
|
||||||
std::string buffer(count, '\0');
|
std::string buffer(count, '\0');
|
||||||
std::size_t n = 0, offset = 0;
|
std::size_t n = 0, offset = 0;
|
||||||
do {
|
do {
|
||||||
|
@ -14,58 +14,56 @@
|
|||||||
#include "fmt/core.h"
|
#include "fmt/core.h"
|
||||||
|
|
||||||
#ifndef FMT_USE_FILE_DESCRIPTORS
|
#ifndef FMT_USE_FILE_DESCRIPTORS
|
||||||
# define FMT_USE_FILE_DESCRIPTORS 0
|
# define FMT_USE_FILE_DESCRIPTORS 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FMT_USE_FILE_DESCRIPTORS
|
#if FMT_USE_FILE_DESCRIPTORS
|
||||||
# include "fmt/posix.h"
|
# include "fmt/posix.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \
|
#define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \
|
||||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||||
if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
|
if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
|
||||||
std::string gtest_expected_message = expected_message; \
|
std::string gtest_expected_message = expected_message; \
|
||||||
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 << #statement \
|
||||||
gtest_ar \
|
" throws an exception with a different message.\n" \
|
||||||
<< #statement " 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 (...) { \
|
||||||
} \
|
gtest_ar << "Expected: " #statement \
|
||||||
catch (...) { \
|
" throws an exception of type " #expected_exception \
|
||||||
gtest_ar << \
|
".\n Actual: it throws a different type."; \
|
||||||
"Expected: " #statement " throws an exception of type " \
|
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||||
#expected_exception ".\n Actual: it throws a different type."; \
|
} \
|
||||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
if (!gtest_caught_expected) { \
|
||||||
} \
|
gtest_ar << "Expected: " #statement \
|
||||||
if (!gtest_caught_expected) { \
|
" throws an exception of type " #expected_exception \
|
||||||
gtest_ar << \
|
".\n Actual: it throws nothing."; \
|
||||||
"Expected: " #statement " throws an exception of type " \
|
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||||
#expected_exception ".\n Actual: it throws nothing."; \
|
} \
|
||||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
} else \
|
||||||
} \
|
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
|
||||||
} else \
|
: fail(gtest_ar.failure_message())
|
||||||
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
|
|
||||||
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);
|
||||||
|
|
||||||
#define EXPECT_SYSTEM_ERROR(statement, error_code, message) \
|
#define EXPECT_SYSTEM_ERROR(statement, error_code, message) \
|
||||||
EXPECT_THROW_MSG(statement, fmt::system_error, \
|
EXPECT_THROW_MSG(statement, fmt::system_error, \
|
||||||
format_system_error(error_code, message))
|
format_system_error(error_code, message))
|
||||||
|
|
||||||
#if FMT_USE_FILE_DESCRIPTORS
|
#if FMT_USE_FILE_DESCRIPTORS
|
||||||
|
|
||||||
@ -73,7 +71,7 @@ std::string format_system_error(int error_code, fmt::string_view message);
|
|||||||
// The output it can handle is limited by the pipe capacity.
|
// The output it can handle is limited by the pipe capacity.
|
||||||
class OutputRedirect {
|
class OutputRedirect {
|
||||||
private:
|
private:
|
||||||
FILE *file_;
|
FILE* file_;
|
||||||
fmt::file original_; // Original file passed to redirector.
|
fmt::file original_; // Original file passed to redirector.
|
||||||
fmt::file read_end_; // Read end of the pipe where the output is redirected.
|
fmt::file read_end_; // Read end of the pipe where the output is redirected.
|
||||||
|
|
||||||
@ -83,7 +81,7 @@ class OutputRedirect {
|
|||||||
void restore();
|
void restore();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit OutputRedirect(FILE *file);
|
explicit OutputRedirect(FILE* file);
|
||||||
~OutputRedirect() FMT_NOEXCEPT;
|
~OutputRedirect() FMT_NOEXCEPT;
|
||||||
|
|
||||||
// Restores the original file, reads output from the pipe into a string
|
// Restores the original file, reads output from the pipe into a string
|
||||||
@ -91,29 +89,28 @@ class OutputRedirect {
|
|||||||
std::string restore_and_read();
|
std::string restore_and_read();
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FMT_TEST_WRITE_(statement, expected_output, file, fail) \
|
# define FMT_TEST_WRITE_(statement, expected_output, file, fail) \
|
||||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||||
if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
|
if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
|
||||||
std::string gtest_expected_output = expected_output; \
|
std::string gtest_expected_output = expected_output; \
|
||||||
OutputRedirect gtest_redir(file); \
|
OutputRedirect gtest_redir(file); \
|
||||||
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) \
|
||||||
FMT_TEST_WRITE_(statement, expected_output, file, GTEST_NONFATAL_FAILURE_)
|
FMT_TEST_WRITE_(statement, expected_output, file, GTEST_NONFATAL_FAILURE_)
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
# ifdef _MSC_VER
|
||||||
|
|
||||||
// Suppresses Windows assertions on invalid file descriptors, making
|
// Suppresses Windows assertions on invalid file descriptors, making
|
||||||
// POSIX functions return proper error codes instead of crashing on Windows.
|
// POSIX functions return proper error codes instead of crashing on Windows.
|
||||||
@ -122,38 +119,41 @@ 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) \
|
||||||
#else
|
{ \
|
||||||
# define SUPPRESS_ASSERT(statement) statement
|
SuppressAssert sa; \
|
||||||
#endif // _MSC_VER
|
statement; \
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
# define SUPPRESS_ASSERT(statement) statement
|
||||||
|
# endif // _MSC_VER
|
||||||
|
|
||||||
#define EXPECT_SYSTEM_ERROR_NOASSERT(statement, error_code, message) \
|
# define EXPECT_SYSTEM_ERROR_NOASSERT(statement, error_code, message) \
|
||||||
EXPECT_SYSTEM_ERROR(SUPPRESS_ASSERT(statement), error_code, message)
|
EXPECT_SYSTEM_ERROR(SUPPRESS_ASSERT(statement), error_code, message)
|
||||||
|
|
||||||
// Attempts to read count characters from a file.
|
// Attempts to read count characters from a file.
|
||||||
std::string read(fmt::file &f, std::size_t count);
|
std::string read(fmt::file& f, std::size_t count);
|
||||||
|
|
||||||
#define EXPECT_READ(file, expected_content) \
|
# define EXPECT_READ(file, expected_content) \
|
||||||
EXPECT_EQ(expected_content, read(file, std::strlen(expected_content)))
|
EXPECT_EQ(expected_content, read(file, std::strlen(expected_content)))
|
||||||
|
|
||||||
#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; }
|
||||||
};
|
};
|
||||||
|
@ -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 '~'; }
|
||||||
};
|
};
|
||||||
|
@ -8,25 +8,23 @@
|
|||||||
#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&) {}
|
||||||
typedef T value_type;
|
typedef T value_type;
|
||||||
MOCK_METHOD1_T(allocate, T* (std::size_t n));
|
MOCK_METHOD1_T(allocate, T*(std::size_t n));
|
||||||
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_;
|
||||||
|
|
||||||
void move(allocator_ref &other) {
|
void move(allocator_ref& other) {
|
||||||
alloc_ = other.alloc_;
|
alloc_ = other.alloc_;
|
||||||
other.alloc_ = FMT_NULL;
|
other.alloc_ = FMT_NULL;
|
||||||
}
|
}
|
||||||
@ -34,24 +32,24 @@ class allocator_ref {
|
|||||||
public:
|
public:
|
||||||
typedef typename Allocator::value_type value_type;
|
typedef typename Allocator::value_type value_type;
|
||||||
|
|
||||||
explicit allocator_ref(Allocator *alloc = FMT_NULL) : alloc_(alloc) {}
|
explicit allocator_ref(Allocator* alloc = FMT_NULL) : alloc_(alloc) {}
|
||||||
|
|
||||||
allocator_ref(const allocator_ref &other) : alloc_(other.alloc_) {}
|
allocator_ref(const allocator_ref& other) : alloc_(other.alloc_) {}
|
||||||
allocator_ref(allocator_ref &&other) { move(other); }
|
allocator_ref(allocator_ref&& other) { move(other); }
|
||||||
|
|
||||||
allocator_ref& operator=(allocator_ref &&other) {
|
allocator_ref& operator=(allocator_ref&& other) {
|
||||||
assert(this != &other);
|
assert(this != &other);
|
||||||
move(other);
|
move(other);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
allocator_ref& operator=(const allocator_ref &other) {
|
allocator_ref& operator=(const allocator_ref& other) {
|
||||||
alloc_ = other.alloc_;
|
alloc_ = other.alloc_;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Allocator *get() const { return alloc_; }
|
Allocator* get() const { return alloc_; }
|
||||||
|
|
||||||
value_type* allocate(std::size_t n) {
|
value_type* allocate(std::size_t n) {
|
||||||
return fmt::internal::allocate(*alloc_, n);
|
return fmt::internal::allocate(*alloc_, n);
|
||||||
|
@ -16,26 +16,26 @@
|
|||||||
using fmt::format;
|
using fmt::format;
|
||||||
using fmt::format_error;
|
using fmt::format_error;
|
||||||
|
|
||||||
static std::ostream &operator<<(std::ostream &os, const Date &d) {
|
static std::ostream& operator<<(std::ostream& os, const Date& d) {
|
||||||
os << d.year() << '-' << d.month() << '-' << d.day();
|
os << d.year() << '-' << d.month() << '-' << d.day();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::wostream &operator<<(std::wostream &os, const Date &d) {
|
static std::wostream& operator<<(std::wostream& os, const Date& d) {
|
||||||
os << d.year() << L'-' << d.month() << L'-' << d.day();
|
os << d.year() << L'-' << d.month() << L'-' << d.day();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TestEnum {};
|
enum TestEnum {};
|
||||||
static std::ostream &operator<<(std::ostream &os, TestEnum) {
|
static std::ostream& operator<<(std::ostream& os, TestEnum) {
|
||||||
return os << "TestEnum";
|
return os << "TestEnum";
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::wostream &operator<<(std::wostream &os, TestEnum) {
|
static std::wostream& operator<<(std::wostream& os, TestEnum) {
|
||||||
return os << L"TestEnum";
|
return os << L"TestEnum";
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TestEnum2 {A};
|
enum TestEnum2 { A };
|
||||||
|
|
||||||
TEST(OStreamTest, Enum) {
|
TEST(OStreamTest, Enum) {
|
||||||
EXPECT_FALSE((fmt::convert_to_int<TestEnum, char>::value));
|
EXPECT_FALSE((fmt::convert_to_int<TestEnum, char>::value));
|
||||||
@ -48,14 +48,14 @@ TEST(OStreamTest, Enum) {
|
|||||||
|
|
||||||
typedef fmt::back_insert_range<fmt::internal::buffer> range;
|
typedef fmt::back_insert_range<fmt::internal::buffer> range;
|
||||||
|
|
||||||
struct test_arg_formatter: fmt::arg_formatter<range> {
|
struct test_arg_formatter : fmt::arg_formatter<range> {
|
||||||
test_arg_formatter(fmt::format_context &ctx, fmt::format_specs &s)
|
test_arg_formatter(fmt::format_context& ctx, fmt::format_specs& s)
|
||||||
: fmt::arg_formatter<range>(ctx, &s) {}
|
: fmt::arg_formatter<range>(ctx, &s) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(OStreamTest, CustomArg) {
|
TEST(OStreamTest, CustomArg) {
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
fmt::internal::buffer &base = buffer;
|
fmt::internal::buffer& base = buffer;
|
||||||
fmt::format_context ctx(std::back_inserter(base), "", fmt::format_args());
|
fmt::format_context ctx(std::back_inserter(base), "", fmt::format_args());
|
||||||
fmt::format_specs spec;
|
fmt::format_specs spec;
|
||||||
test_arg_formatter af(ctx, spec);
|
test_arg_formatter af(ctx, spec);
|
||||||
@ -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")));
|
||||||
@ -96,7 +96,7 @@ TEST(OStreamTest, FormatSpecs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct EmptyTest {};
|
struct EmptyTest {};
|
||||||
static std::ostream &operator<<(std::ostream &os, EmptyTest) {
|
static std::ostream& operator<<(std::ostream& os, EmptyTest) {
|
||||||
return os << "";
|
return os << "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ TEST(OStreamTest, Print) {
|
|||||||
TEST(OStreamTest, WriteToOStream) {
|
TEST(OStreamTest, WriteToOStream) {
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
const char *foo = "foo";
|
const char* foo = "foo";
|
||||||
buffer.append(foo, foo + std::strlen(foo));
|
buffer.append(foo, foo + std::strlen(foo));
|
||||||
fmt::internal::write(os, buffer);
|
fmt::internal::write(os, buffer);
|
||||||
EXPECT_EQ("foo", os.str());
|
EXPECT_EQ("foo", os.str());
|
||||||
@ -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); }
|
||||||
@ -134,19 +133,19 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
|
|||||||
} buffer(max_size);
|
} buffer(max_size);
|
||||||
|
|
||||||
struct mock_streambuf : std::streambuf {
|
struct mock_streambuf : std::streambuf {
|
||||||
MOCK_METHOD2(xsputn, std::streamsize (const void *s, std::streamsize n));
|
MOCK_METHOD2(xsputn, std::streamsize(const void* s, std::streamsize n));
|
||||||
std::streamsize xsputn(const char *s, std::streamsize n) {
|
std::streamsize xsputn(const char* s, std::streamsize n) {
|
||||||
const void *v = s;
|
const void* v = s;
|
||||||
return xsputn(v, n);
|
return xsputn(v, n);
|
||||||
}
|
}
|
||||||
} streambuf;
|
} streambuf;
|
||||||
|
|
||||||
struct test_ostream : std::ostream {
|
struct test_ostream : std::ostream {
|
||||||
explicit test_ostream(mock_streambuf &buffer) : std::ostream(&buffer) {}
|
explicit test_ostream(mock_streambuf& buffer) : std::ostream(&buffer) {}
|
||||||
} os(streambuf);
|
} os(streambuf);
|
||||||
|
|
||||||
testing::InSequence sequence;
|
testing::InSequence sequence;
|
||||||
const char *data = FMT_NULL;
|
const char* data = FMT_NULL;
|
||||||
typedef std::make_unsigned<std::streamsize>::type ustreamsize;
|
typedef std::make_unsigned<std::streamsize>::type ustreamsize;
|
||||||
ustreamsize size = max_size;
|
ustreamsize size = max_size;
|
||||||
do {
|
do {
|
||||||
@ -173,11 +172,11 @@ TEST(OStreamTest, ConstexprString) {
|
|||||||
namespace fmt_test {
|
namespace fmt_test {
|
||||||
struct ABC {};
|
struct ABC {};
|
||||||
|
|
||||||
template <typename Output> Output &operator<<(Output &out, ABC) {
|
template <typename Output> Output& operator<<(Output& out, ABC) {
|
||||||
out << "ABC";
|
out << "ABC";
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
} // namespace fmt_test
|
} // namespace fmt_test
|
||||||
|
|
||||||
TEST(FormatTest, FormatToN) {
|
TEST(FormatTest, FormatToN) {
|
||||||
char buffer[4];
|
char buffer[4];
|
||||||
|
@ -7,21 +7,21 @@
|
|||||||
|
|
||||||
// Disable bogus MSVC warnings.
|
// Disable bogus MSVC warnings.
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# define _CRT_SECURE_NO_WARNINGS
|
# define _CRT_SECURE_NO_WARNINGS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#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
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
# undef max
|
# undef max
|
||||||
# undef ERROR
|
# undef ERROR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gmock.h"
|
#include "gmock.h"
|
||||||
@ -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,24 +53,24 @@ 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) { \
|
||||||
if (func##_count++ != 3) { \
|
if (func##_count++ != 3) { \
|
||||||
errno = EINTR; \
|
errno = EINTR; \
|
||||||
return error_result; \
|
return error_result; \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
int test::open(const char *path, int oflag, int mode) {
|
int test::open(const char* path, int oflag, int mode) {
|
||||||
EMULATE_EINTR(open, -1);
|
EMULATE_EINTR(open, -1);
|
||||||
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;
|
||||||
@ -89,10 +88,9 @@ long test::sysconf(int name) {
|
|||||||
|
|
||||||
static off_t max_file_size() { return std::numeric_limits<off_t>::max(); }
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,18 +130,18 @@ int test::dup2(int fildes, int fildes2) {
|
|||||||
return ::FMT_POSIX(dup2(fildes, fildes2));
|
return ::FMT_POSIX(dup2(fildes, fildes2));
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *test::fdopen(int fildes, const char *mode) {
|
FILE* test::fdopen(int fildes, const char* mode) {
|
||||||
EMULATE_EINTR(fdopen, FMT_NULL);
|
EMULATE_EINTR(fdopen, FMT_NULL);
|
||||||
return ::FMT_POSIX(fdopen(fildes, mode));
|
return ::FMT_POSIX(fdopen(fildes, mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
test::ssize_t test::read(int fildes, void *buf, test::size_t nbyte) {
|
test::ssize_t test::read(int fildes, void* buf, test::size_t nbyte) {
|
||||||
read_nbyte = nbyte;
|
read_nbyte = nbyte;
|
||||||
EMULATE_EINTR(read, -1);
|
EMULATE_EINTR(read, -1);
|
||||||
return ::FMT_POSIX(read(fildes, buf, nbyte));
|
return ::FMT_POSIX(read(fildes, buf, nbyte));
|
||||||
}
|
}
|
||||||
|
|
||||||
test::ssize_t test::write(int fildes, const void *buf, test::size_t nbyte) {
|
test::ssize_t test::write(int fildes, const void* buf, test::size_t nbyte) {
|
||||||
write_nbyte = nbyte;
|
write_nbyte = nbyte;
|
||||||
EMULATE_EINTR(write, -1);
|
EMULATE_EINTR(write, -1);
|
||||||
return ::FMT_POSIX(write(fildes, buf, nbyte));
|
return ::FMT_POSIX(write(fildes, buf, nbyte));
|
||||||
@ -155,23 +153,23 @@ int test::pipe(int fildes[2]) {
|
|||||||
return ::pipe(fildes);
|
return ::pipe(fildes);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
int test::pipe(int *pfds, unsigned psize, int textmode) {
|
int test::pipe(int* pfds, unsigned psize, int textmode) {
|
||||||
EMULATE_EINTR(pipe, -1);
|
EMULATE_EINTR(pipe, -1);
|
||||||
return _pipe(pfds, psize, textmode);
|
return _pipe(pfds, psize, textmode);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FILE *test::fopen(const char *filename, const char *mode) {
|
FILE* test::fopen(const char* filename, const char* mode) {
|
||||||
EMULATE_EINTR(fopen, FMT_NULL);
|
EMULATE_EINTR(fopen, FMT_NULL);
|
||||||
return ::fopen(filename, mode);
|
return ::fopen(filename, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
int test::fclose(FILE *stream) {
|
int test::fclose(FILE* stream) {
|
||||||
EMULATE_EINTR(fclose, EOF);
|
EMULATE_EINTR(fclose, EOF);
|
||||||
return ::fclose(stream);
|
return ::fclose(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
int (test::fileno)(FILE *stream) {
|
int(test::fileno)(FILE* stream) {
|
||||||
EMULATE_EINTR(fileno, -1);
|
EMULATE_EINTR(fileno, -1);
|
||||||
#ifdef fileno
|
#ifdef fileno
|
||||||
return FMT_POSIX(fileno(stream));
|
return FMT_POSIX(fileno(stream));
|
||||||
@ -181,18 +179,18 @@ int (test::fileno)(FILE *stream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
# define EXPECT_RETRY(statement, func, message) \
|
# define EXPECT_RETRY(statement, func, message) \
|
||||||
func##_count = 1; \
|
func##_count = 1; \
|
||||||
statement; \
|
statement; \
|
||||||
EXPECT_EQ(4, func##_count); \
|
EXPECT_EQ(4, func##_count); \
|
||||||
func##_count = 0;
|
func##_count = 0;
|
||||||
# define EXPECT_EQ_POSIX(expected, actual) EXPECT_EQ(expected, actual)
|
# define EXPECT_EQ_POSIX(expected, actual) EXPECT_EQ(expected, actual)
|
||||||
#else
|
#else
|
||||||
# define EXPECT_RETRY(statement, func, message) \
|
# define EXPECT_RETRY(statement, func, message) \
|
||||||
func##_count = 1; \
|
func##_count = 1; \
|
||||||
EXPECT_SYSTEM_ERROR(statement, EINTR, message); \
|
EXPECT_SYSTEM_ERROR(statement, EINTR, message); \
|
||||||
func##_count = 0;
|
func##_count = 0;
|
||||||
# define EXPECT_EQ_POSIX(expected, actual)
|
# define EXPECT_EQ_POSIX(expected, actual)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void write_file(fmt::cstring_view filename, fmt::string_view content) {
|
static void write_file(fmt::cstring_view filename, fmt::string_view content) {
|
||||||
@ -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;
|
{
|
||||||
f.reset(FMT_NULL);
|
close_count = 1;
|
||||||
saved_close_count = close_count;
|
f.reset(FMT_NULL);
|
||||||
close_count = 0;
|
saved_close_count = close_count;
|
||||||
}, format_system_error(EINTR, "cannot close file") + "\n");
|
close_count = 0;
|
||||||
|
},
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
@ -348,8 +347,8 @@ TEST(FileTest, Dup2Retry) {
|
|||||||
int stdout_fd = FMT_POSIX(fileno(stdout));
|
int stdout_fd = FMT_POSIX(fileno(stdout));
|
||||||
file f1 = file::dup(stdout_fd), f2 = file::dup(stdout_fd);
|
file f1 = file::dup(stdout_fd), f2 = file::dup(stdout_fd);
|
||||||
EXPECT_RETRY(f1.dup2(f2.descriptor()), dup2,
|
EXPECT_RETRY(f1.dup2(f2.descriptor()), dup2,
|
||||||
fmt::format("cannot duplicate file descriptor {} to {}",
|
fmt::format("cannot duplicate file descriptor {} to {}",
|
||||||
f1.descriptor(), f2.descriptor()));
|
f1.descriptor(), f2.descriptor()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileTest, Dup2NoExceptRetry) {
|
TEST(FileTest, Dup2NoExceptRetry) {
|
||||||
@ -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;
|
{
|
||||||
f.reset(FMT_NULL);
|
fclose_count = 1;
|
||||||
saved_fclose_count = fclose_count;
|
f.reset(FMT_NULL);
|
||||||
fclose_count = 0;
|
saved_fclose_count = fclose_count;
|
||||||
}, format_system_error(EINTR, "cannot close file") + "\n");
|
fclose_count = 0;
|
||||||
|
},
|
||||||
|
format_system_error(EINTR, "cannot close file") + "\n");
|
||||||
EXPECT_EQ(2, saved_fclose_count);
|
EXPECT_EQ(2, saved_fclose_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,14 +431,14 @@ TEST(BufferedFileTest, FilenoNoRetry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct TestMock {
|
struct TestMock {
|
||||||
static TestMock *instance;
|
static TestMock* instance;
|
||||||
} *TestMock::instance;
|
} * TestMock::instance;
|
||||||
|
|
||||||
TEST(ScopedMock, Scope) {
|
TEST(ScopedMock, Scope) {
|
||||||
{
|
{
|
||||||
ScopedMock<TestMock> mock;
|
ScopedMock<TestMock> mock;
|
||||||
EXPECT_EQ(&mock, TestMock::instance);
|
EXPECT_EQ(&mock, TestMock::instance);
|
||||||
TestMock © = mock;
|
TestMock& copy = mock;
|
||||||
static_cast<void>(copy);
|
static_cast<void>(copy);
|
||||||
}
|
}
|
||||||
EXPECT_EQ(FMT_NULL, TestMock::instance);
|
EXPECT_EQ(FMT_NULL, TestMock::instance);
|
||||||
@ -448,20 +449,20 @@ TEST(ScopedMock, Scope) {
|
|||||||
typedef fmt::Locale::Type LocaleType;
|
typedef fmt::Locale::Type LocaleType;
|
||||||
|
|
||||||
struct LocaleMock {
|
struct LocaleMock {
|
||||||
static LocaleMock *instance;
|
static LocaleMock* instance;
|
||||||
MOCK_METHOD3(newlocale, LocaleType (int category_mask, const char *locale,
|
MOCK_METHOD3(newlocale, LocaleType(int category_mask, const char* locale,
|
||||||
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
|
||||||
# pragma warning(push)
|
# pragma warning(push)
|
||||||
# pragma warning(disable: 4273)
|
# pragma warning(disable : 4273)
|
||||||
|
|
||||||
_locale_t _create_locale(int category, const char *locale) {
|
_locale_t _create_locale(int category, const char* locale) {
|
||||||
return LocaleMock::instance->newlocale(category, locale, 0);
|
return LocaleMock::instance->newlocale(category, locale, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,38 +470,41 @@ void _free_locale(_locale_t locale) {
|
|||||||
LocaleMock::instance->freelocale(locale);
|
LocaleMock::instance->freelocale(locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
double _strtod_l(const char *nptr, char **endptr, _locale_t locale) {
|
double _strtod_l(const char* nptr, char** endptr, _locale_t locale) {
|
||||||
return LocaleMock::instance->strtod_l(nptr, endptr, locale);
|
return LocaleMock::instance->strtod_l(nptr, endptr, locale);
|
||||||
}
|
}
|
||||||
# pragma warning(pop)
|
# pragma warning(pop)
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#if defined(__THROW) && FMT_GCC_VERSION > 0 && FMT_GCC_VERSION <= 408
|
# if defined(__THROW) && FMT_GCC_VERSION > 0 && FMT_GCC_VERSION <= 408
|
||||||
#define FMT_LOCALE_THROW __THROW
|
# define FMT_LOCALE_THROW __THROW
|
||||||
#else
|
# else
|
||||||
#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;
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
FreeLocaleResult freelocale(LocaleType locale) FMT_LOCALE_THROW {
|
FreeLocaleResult freelocale(LocaleType locale) FMT_LOCALE_THROW {
|
||||||
LocaleMock::instance->freelocale(locale);
|
LocaleMock::instance->freelocale(locale);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef FMT_LOCALE_THROW
|
# undef FMT_LOCALE_THROW
|
||||||
|
|
||||||
TEST(LocaleTest, LocaleMock) {
|
TEST(LocaleTest, LocaleMock) {
|
||||||
ScopedMock<LocaleMock> mock;
|
ScopedMock<LocaleMock> mock;
|
||||||
@ -510,9 +514,9 @@ TEST(LocaleTest, LocaleMock) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(LocaleTest, Locale) {
|
TEST(LocaleTest, Locale) {
|
||||||
#ifndef LC_NUMERIC_MASK
|
# ifndef LC_NUMERIC_MASK
|
||||||
enum { LC_NUMERIC_MASK = LC_NUMERIC };
|
enum { LC_NUMERIC_MASK = LC_NUMERIC };
|
||||||
#endif
|
# endif
|
||||||
ScopedMock<LocaleMock> mock;
|
ScopedMock<LocaleMock> mock;
|
||||||
LocaleType impl = reinterpret_cast<LocaleType>(42);
|
LocaleType impl = reinterpret_cast<LocaleType>(42);
|
||||||
EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), FMT_NULL))
|
EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), FMT_NULL))
|
||||||
@ -528,7 +532,7 @@ TEST(LocaleTest, Strtod) {
|
|||||||
.WillOnce(Return(reinterpret_cast<LocaleType>(42)));
|
.WillOnce(Return(reinterpret_cast<LocaleType>(42)));
|
||||||
EXPECT_CALL(mock, freelocale(_));
|
EXPECT_CALL(mock, freelocale(_));
|
||||||
fmt::Locale locale;
|
fmt::Locale locale;
|
||||||
const char *str = "4.2";
|
const char* str = "4.2";
|
||||||
char end = 'x';
|
char end = 'x';
|
||||||
EXPECT_CALL(mock, strtod_l(str, _, locale.get()))
|
EXPECT_CALL(mock, strtod_l(str, _, locale.get()))
|
||||||
.WillOnce(testing::DoAll(testing::SetArgPointee<1>(&end), Return(777)));
|
.WillOnce(testing::DoAll(testing::SetArgPointee<1>(&end), Return(777)));
|
||||||
|
@ -12,10 +12,10 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#else
|
#else
|
||||||
# include <sys/param.h> // for FreeBSD version
|
# include <sys/param.h> // for FreeBSD version
|
||||||
# include <sys/types.h> // for ssize_t
|
# include <sys/types.h> // for ssize_t
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
@ -28,13 +28,13 @@ namespace test {
|
|||||||
// Size type for read and write.
|
// Size type for read and write.
|
||||||
typedef size_t size_t;
|
typedef size_t size_t;
|
||||||
typedef ssize_t ssize_t;
|
typedef ssize_t ssize_t;
|
||||||
int open(const char *path, int oflag, int mode);
|
int open(const char* path, int oflag, int mode);
|
||||||
int fstat(int fd, struct stat *buf);
|
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
|
||||||
@ -48,20 +48,20 @@ int close(int fildes);
|
|||||||
int dup(int fildes);
|
int dup(int fildes);
|
||||||
int dup2(int fildes, int fildes2);
|
int dup2(int fildes, int fildes2);
|
||||||
|
|
||||||
FILE *fdopen(int fildes, const char *mode);
|
FILE* fdopen(int fildes, const char* mode);
|
||||||
|
|
||||||
ssize_t read(int fildes, void *buf, size_t nbyte);
|
ssize_t read(int fildes, void* buf, size_t nbyte);
|
||||||
ssize_t write(int fildes, const void *buf, size_t nbyte);
|
ssize_t write(int fildes, const void* buf, size_t nbyte);
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
int pipe(int fildes[2]);
|
int pipe(int fildes[2]);
|
||||||
#else
|
#else
|
||||||
int pipe(int *pfds, unsigned psize, int textmode);
|
int pipe(int* pfds, unsigned psize, int textmode);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FILE *fopen(const char *filename, const char *mode);
|
FILE* fopen(const char* filename, const char* mode);
|
||||||
int fclose(FILE *stream);
|
int fclose(FILE* stream);
|
||||||
int (fileno)(FILE *stream);
|
int(fileno)(FILE* stream);
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|
||||||
#define FMT_SYSTEM(call) test::call
|
#define FMT_SYSTEM(call) test::call
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#ifdef fileno
|
#ifdef fileno
|
||||||
# undef fileno
|
# undef fileno
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using fmt::buffered_file;
|
using fmt::buffered_file;
|
||||||
@ -44,9 +44,9 @@ static file open_file() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to write a string to a file.
|
// Attempts to write a string to a file.
|
||||||
static void write(file &f, fmt::string_view s) {
|
static void write(file& f, fmt::string_view s) {
|
||||||
std::size_t num_chars_left = s.size();
|
std::size_t num_chars_left = s.size();
|
||||||
const char *ptr = s.data();
|
const char* ptr = s.data();
|
||||||
do {
|
do {
|
||||||
std::size_t count = f.write(ptr, num_chars_left);
|
std::size_t count = f.write(ptr, num_chars_left);
|
||||||
ptr += count;
|
ptr += count;
|
||||||
@ -63,7 +63,7 @@ TEST(BufferedFileTest, DefaultCtor) {
|
|||||||
|
|
||||||
TEST(BufferedFileTest, MoveCtor) {
|
TEST(BufferedFileTest, MoveCtor) {
|
||||||
buffered_file bf = open_buffered_file();
|
buffered_file bf = open_buffered_file();
|
||||||
FILE *fp = bf.get();
|
FILE* fp = bf.get();
|
||||||
EXPECT_TRUE(fp != FMT_NULL);
|
EXPECT_TRUE(fp != FMT_NULL);
|
||||||
buffered_file bf2(std::move(bf));
|
buffered_file bf2(std::move(bf));
|
||||||
EXPECT_EQ(fp, bf2.get());
|
EXPECT_EQ(fp, bf2.get());
|
||||||
@ -72,7 +72,7 @@ TEST(BufferedFileTest, MoveCtor) {
|
|||||||
|
|
||||||
TEST(BufferedFileTest, MoveAssignment) {
|
TEST(BufferedFileTest, MoveAssignment) {
|
||||||
buffered_file bf = open_buffered_file();
|
buffered_file bf = open_buffered_file();
|
||||||
FILE *fp = bf.get();
|
FILE* fp = bf.get();
|
||||||
EXPECT_TRUE(fp != FMT_NULL);
|
EXPECT_TRUE(fp != FMT_NULL);
|
||||||
buffered_file bf2;
|
buffered_file bf2;
|
||||||
bf2 = std::move(bf);
|
bf2 = std::move(bf);
|
||||||
@ -89,13 +89,13 @@ TEST(BufferedFileTest, MoveAssignmentClosesFile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(BufferedFileTest, MoveFromTemporaryInCtor) {
|
TEST(BufferedFileTest, MoveFromTemporaryInCtor) {
|
||||||
FILE *fp = FMT_NULL;
|
FILE* fp = FMT_NULL;
|
||||||
buffered_file f(open_buffered_file(&fp));
|
buffered_file f(open_buffered_file(&fp));
|
||||||
EXPECT_EQ(fp, f.get());
|
EXPECT_EQ(fp, f.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BufferedFileTest, MoveFromTemporaryInAssignment) {
|
TEST(BufferedFileTest, MoveFromTemporaryInAssignment) {
|
||||||
FILE *fp = FMT_NULL;
|
FILE* fp = FMT_NULL;
|
||||||
buffered_file f;
|
buffered_file f;
|
||||||
f = open_buffered_file(&fp);
|
f = open_buffered_file(&fp);
|
||||||
EXPECT_EQ(fp, f.get());
|
EXPECT_EQ(fp, f.get());
|
||||||
@ -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
|
||||||
FMT_POSIX(close(f->fileno()));
|
// will break output redirection.
|
||||||
SUPPRESS_ASSERT(f.reset(FMT_NULL));
|
FMT_POSIX(close(f->fileno()));
|
||||||
}, format_system_error(EBADF, "cannot close file") + "\n");
|
SUPPRESS_ASSERT(f.reset(FMT_NULL));
|
||||||
|
},
|
||||||
|
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 {
|
{
|
||||||
f.fileno();
|
try {
|
||||||
} catch (const fmt::system_error&) {
|
f.fileno();
|
||||||
std::exit(1);
|
} catch (const fmt::system_error&) {
|
||||||
}
|
std::exit(1);
|
||||||
}, "");
|
}
|
||||||
|
},
|
||||||
|
"");
|
||||||
#endif
|
#endif
|
||||||
f = open_buffered_file();
|
f = open_buffered_file();
|
||||||
EXPECT_TRUE(f.fileno() != -1);
|
EXPECT_TRUE(f.fileno() != -1);
|
||||||
@ -169,7 +173,7 @@ TEST(FileTest, DefaultCtor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileTest, OpenBufferedFileInCtor) {
|
TEST(FileTest, OpenBufferedFileInCtor) {
|
||||||
FILE *fp = safe_fopen("test-file", "w");
|
FILE* fp = safe_fopen("test-file", "w");
|
||||||
std::fputs(FILE_CONTENT, fp);
|
std::fputs(FILE_CONTENT, fp);
|
||||||
std::fclose(fp);
|
std::fclose(fp);
|
||||||
file f("test-file", file::RDONLY);
|
file f("test-file", file::RDONLY);
|
||||||
@ -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) {
|
||||||
@ -208,7 +212,7 @@ TEST(FileTest, MoveAssignmentClosesFile) {
|
|||||||
EXPECT_TRUE(isclosed(old_fd));
|
EXPECT_TRUE(isclosed(old_fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
static file OpenBufferedFile(int &fd) {
|
static file OpenBufferedFile(int& fd) {
|
||||||
file f = open_file();
|
file f = open_file();
|
||||||
fd = f.descriptor();
|
fd = f.descriptor();
|
||||||
return f;
|
return f;
|
||||||
@ -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
|
||||||
FMT_POSIX(close(f->descriptor()));
|
// will break output redirection.
|
||||||
SUPPRESS_ASSERT(f.reset(FMT_NULL));
|
FMT_POSIX(close(f->descriptor()));
|
||||||
}, format_system_error(EBADF, "cannot close file") + "\n");
|
SUPPRESS_ASSERT(f.reset(FMT_NULL));
|
||||||
|
},
|
||||||
|
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,8 +330,9 @@ 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(
|
||||||
fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor()));
|
f.dup2(-1), EBADF,
|
||||||
|
fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileTest, Dup2NoExcept) {
|
TEST(FileTest, Dup2NoExcept) {
|
||||||
@ -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
|
||||||
|
@ -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,12 +14,11 @@
|
|||||||
#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.
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
# include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "fmt/prepare.h"
|
#include "fmt/prepare.h"
|
||||||
@ -35,24 +35,24 @@ using testing::Return;
|
|||||||
using testing::StrictMock;
|
using testing::StrictMock;
|
||||||
|
|
||||||
class mock_parts_collector {
|
class mock_parts_collector {
|
||||||
public:
|
public:
|
||||||
MOCK_METHOD1(add, void(fmt::format_part<char>));
|
MOCK_METHOD1(add, void(fmt::format_part<char>));
|
||||||
MOCK_METHOD1(substitute_last, void(fmt::format_part<char>));
|
MOCK_METHOD1(substitute_last, void(fmt::format_part<char>));
|
||||||
MOCK_METHOD0(last, fmt::format_part<char>());
|
MOCK_METHOD0(last, fmt::format_part<char>());
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
bool operator==(const internal::string_view_metadata &lhs,
|
bool operator==(const internal::string_view_metadata& lhs,
|
||||||
const internal::string_view_metadata &rhs) {
|
const internal::string_view_metadata& rhs) {
|
||||||
return std::tie(lhs.offset_, lhs.size_) == std::tie(rhs.offset_, rhs.size_);
|
return std::tie(lhs.offset_, lhs.size_) == std::tie(rhs.offset_, rhs.size_);
|
||||||
}
|
}
|
||||||
bool operator!=(const internal::string_view_metadata &lhs,
|
bool operator!=(const internal::string_view_metadata& lhs,
|
||||||
const internal::string_view_metadata &rhs) {
|
const internal::string_view_metadata& rhs) {
|
||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const format_part<char>::specification &lhs,
|
bool operator==(const format_part<char>::specification& lhs,
|
||||||
const format_part<char>::specification &rhs) {
|
const format_part<char>::specification& rhs) {
|
||||||
if (lhs.arg_id.which != rhs.arg_id.which) {
|
if (lhs.arg_id.which != rhs.arg_id.which) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -79,13 +79,13 @@ bool operator==(const format_part<char>::specification &lhs,
|
|||||||
rhs.parsed_specs.flags, rhs.parsed_specs.type);
|
rhs.parsed_specs.flags, rhs.parsed_specs.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const format_part<char>::specification &lhs,
|
bool operator!=(const format_part<char>::specification& lhs,
|
||||||
const format_part<char>::specification &rhs) {
|
const format_part<char>::specification& rhs) {
|
||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const format_part<char> &lhs,
|
bool operator==(const format_part<char>& lhs,
|
||||||
const fmt::format_part<char> &rhs) {
|
const fmt::format_part<char>& rhs) {
|
||||||
typedef format_part<char>::which_value which_value;
|
typedef format_part<char>::which_value which_value;
|
||||||
|
|
||||||
if (lhs.which != rhs.which ||
|
if (lhs.which != rhs.which ||
|
||||||
@ -114,8 +114,8 @@ bool operator==(const format_part<char> &lhs,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const fmt::format_part<char> &lhs,
|
bool operator!=(const fmt::format_part<char>& lhs,
|
||||||
const fmt::format_part<char> &rhs) {
|
const fmt::format_part<char>& rhs) {
|
||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
@ -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);
|
||||||
@ -423,13 +425,13 @@ TEST(PrepareTest, CompileTimePreparedPartsTypeProvider) {
|
|||||||
check_prepared_parts_type<3u>(FMT_STRING("text{}text"));
|
check_prepared_parts_type<3u>(FMT_STRING("text{}text"));
|
||||||
check_prepared_parts_type<3u>(FMT_STRING("{:{}.{}} {:{}}"));
|
check_prepared_parts_type<3u>(FMT_STRING("{:{}.{}} {:{}}"));
|
||||||
|
|
||||||
check_prepared_parts_type<3u>(FMT_STRING("{{{}}}")); // '{', 'argument', '}'
|
check_prepared_parts_type<3u>(FMT_STRING("{{{}}}")); // '{', 'argument', '}'
|
||||||
check_prepared_parts_type<2u>(FMT_STRING("text{{")); // 'text', '{'
|
check_prepared_parts_type<2u>(FMT_STRING("text{{")); // 'text', '{'
|
||||||
check_prepared_parts_type<3u>(FMT_STRING("text{{ ")); // 'text', '{', ' '
|
check_prepared_parts_type<3u>(FMT_STRING("text{{ ")); // 'text', '{', ' '
|
||||||
check_prepared_parts_type<2u>(FMT_STRING("}}text")); // '}', text
|
check_prepared_parts_type<2u>(FMT_STRING("}}text")); // '}', text
|
||||||
check_prepared_parts_type<2u>(FMT_STRING("text}}text")); // 'text}', 'text'
|
check_prepared_parts_type<2u>(FMT_STRING("text}}text")); // 'text}', 'text'
|
||||||
check_prepared_parts_type<4u>(
|
check_prepared_parts_type<4u>(
|
||||||
FMT_STRING("text{{}}text")); // 'text', '{', '}', 'text'
|
FMT_STRING("text{{}}text")); // 'text', '{', '}', 'text'
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -500,13 +502,13 @@ TEST(PrepareTest, UserProvidedPartsContainerUnderlyingContainer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class custom_parts_container {
|
class custom_parts_container {
|
||||||
public:
|
public:
|
||||||
typedef fmt::format_part<char> format_part_type;
|
typedef fmt::format_part<char> format_part_type;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::deque<format_part_type> parts;
|
typedef std::deque<format_part_type> parts;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void add(format_part_type part) { parts_.push_back(std::move(part)); }
|
void add(format_part_type part) { parts_.push_back(std::move(part)); }
|
||||||
|
|
||||||
void substitute_last(format_part_type part) {
|
void substitute_last(format_part_type part) {
|
||||||
@ -532,7 +534,7 @@ public:
|
|||||||
return parts_.end();
|
return parts_.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
parts parts_;
|
parts parts_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -547,10 +549,10 @@ TEST(PrepareTest, UserProvidedPartsContainer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrepareTest, PassConstCharPointerFormat) {
|
TEST(PrepareTest, PassConstCharPointerFormat) {
|
||||||
const char *c_format = "test {}";
|
const char* c_format = "test {}";
|
||||||
const auto prepared = fmt::prepare<int>(c_format);
|
const auto prepared = fmt::prepare<int>(c_format);
|
||||||
EXPECT_EQ("test 42", prepared.format(42));
|
EXPECT_EQ("test 42", prepared.format(42));
|
||||||
const wchar_t *wc_format = L"test {}";
|
const wchar_t* wc_format = L"test {}";
|
||||||
const auto wprepared = fmt::prepare<int>(wc_format);
|
const auto wprepared = fmt::prepare<int>(wc_format);
|
||||||
EXPECT_EQ(L"test 42", wprepared.format(42));
|
EXPECT_EQ(L"test 42", wprepared.format(42));
|
||||||
}
|
}
|
||||||
@ -607,10 +609,10 @@ TEST(PrepareTest, PassCompileString) {
|
|||||||
|
|
||||||
template <typename T> struct user_allocator {
|
template <typename T> struct user_allocator {
|
||||||
typedef T value_type;
|
typedef T value_type;
|
||||||
typedef value_type *pointer;
|
typedef value_type* pointer;
|
||||||
typedef const value_type *const_pointer;
|
typedef const value_type* const_pointer;
|
||||||
typedef value_type &reference;
|
typedef value_type& reference;
|
||||||
typedef const value_type &const_reference;
|
typedef const value_type& const_reference;
|
||||||
typedef std::size_t size_type;
|
typedef std::size_t size_type;
|
||||||
typedef std::ptrdiff_t difference_type;
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
|
||||||
@ -618,7 +620,7 @@ template <typename T> struct user_allocator {
|
|||||||
|
|
||||||
user_allocator() = default;
|
user_allocator() = default;
|
||||||
~user_allocator() = default;
|
~user_allocator() = default;
|
||||||
template <typename U> user_allocator(const user_allocator<U> &) {}
|
template <typename U> user_allocator(const user_allocator<U>&) {}
|
||||||
|
|
||||||
pointer allocate(size_type cnt,
|
pointer allocate(size_type cnt,
|
||||||
typename std::allocator<void>::const_pointer = 0) {
|
typename std::allocator<void>::const_pointer = 0) {
|
||||||
@ -627,12 +629,12 @@ template <typename T> struct user_allocator {
|
|||||||
|
|
||||||
void deallocate(pointer p, size_type cnt) { delete[] p; }
|
void deallocate(pointer p, size_type cnt) { delete[] p; }
|
||||||
|
|
||||||
void construct(pointer p, const value_type &val) { new (p) value_type(val); }
|
void construct(pointer p, const value_type& val) { new (p) value_type(val); }
|
||||||
|
|
||||||
void destroy(pointer p) { (*p).~value_type(); }
|
void destroy(pointer p) { (*p).~value_type(); }
|
||||||
|
|
||||||
bool operator==(const user_allocator &other) const { return true; }
|
bool operator==(const user_allocator& other) const { return true; }
|
||||||
bool operator!=(const user_allocator &other) const { return false; }
|
bool operator!=(const user_allocator& other) const { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(PrepareTest, PassUserTypeFormat) {
|
TEST(PrepareTest, PassUserTypeFormat) {
|
||||||
|
@ -35,17 +35,17 @@ static std::wstring make_positional(fmt::wstring_view format) {
|
|||||||
// A wrapper around fmt::sprintf to workaround bogus warnings about invalid
|
// A wrapper around fmt::sprintf to workaround bogus warnings about invalid
|
||||||
// format strings in MSVC.
|
// format strings in MSVC.
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
std::string test_sprintf(fmt::string_view format, const Args &... args) {
|
std::string test_sprintf(fmt::string_view format, const Args&... args) {
|
||||||
return fmt::sprintf(format, args...);
|
return fmt::sprintf(format, args...);
|
||||||
}
|
}
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
std::wstring test_sprintf(fmt::wstring_view format, const Args &... args) {
|
std::wstring test_sprintf(fmt::wstring_view format, const Args&... args) {
|
||||||
return fmt::sprintf(format, args...);
|
return fmt::sprintf(format, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define EXPECT_PRINTF(expected_output, format, arg) \
|
#define EXPECT_PRINTF(expected_output, format, arg) \
|
||||||
EXPECT_EQ(expected_output, test_sprintf(format, arg)) \
|
EXPECT_EQ(expected_output, test_sprintf(format, arg)) \
|
||||||
<< "format: " << format; \
|
<< "format: " << format; \
|
||||||
EXPECT_EQ(expected_output, fmt::sprintf(make_positional(format), arg))
|
EXPECT_EQ(expected_output, fmt::sprintf(make_positional(format), arg))
|
||||||
|
|
||||||
TEST(PrintfTest, NoArgs) {
|
TEST(PrintfTest, NoArgs) {
|
||||||
@ -69,11 +69,10 @@ TEST(PrintfTest, Escape) {
|
|||||||
TEST(PrintfTest, PositionalArgs) {
|
TEST(PrintfTest, PositionalArgs) {
|
||||||
EXPECT_EQ("42", test_sprintf("%1$d", 42));
|
EXPECT_EQ("42", test_sprintf("%1$d", 42));
|
||||||
EXPECT_EQ("before 42", test_sprintf("before %1$d", 42));
|
EXPECT_EQ("before 42", test_sprintf("before %1$d", 42));
|
||||||
EXPECT_EQ("42 after", test_sprintf("%1$d after",42));
|
EXPECT_EQ("42 after", test_sprintf("%1$d after", 42));
|
||||||
EXPECT_EQ("before 42 after", test_sprintf("before %1$d after", 42));
|
EXPECT_EQ("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,46 +81,46 @@ 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),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, InvalidArgIndex) {
|
TEST(PrintfTest, InvalidArgIndex) {
|
||||||
EXPECT_THROW_MSG(test_sprintf("%0$d", 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%0$d", 42), format_error,
|
||||||
"argument index out of range");
|
"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);
|
||||||
@ -208,23 +207,23 @@ TEST(PrintfTest, Width) {
|
|||||||
|
|
||||||
// Width cannot be specified twice.
|
// Width cannot be specified twice.
|
||||||
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) {
|
||||||
EXPECT_EQ(" 42", test_sprintf("%*d", 5, 42));
|
EXPECT_EQ(" 42", test_sprintf("%*d", 5, 42));
|
||||||
EXPECT_EQ("42 ", test_sprintf("%*d", -5, 42));
|
EXPECT_EQ("42 ", test_sprintf("%*d", -5, 42));
|
||||||
EXPECT_THROW_MSG(test_sprintf("%*d", 5.0, 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%*d", 5.0, 42), format_error,
|
||||||
"width is not integer");
|
"width is not integer");
|
||||||
EXPECT_THROW_MSG(test_sprintf("%*d"), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%*d"), format_error,
|
||||||
"argument index out of range");
|
"argument index out of range");
|
||||||
EXPECT_THROW_MSG(test_sprintf("%*d", BIG_NUM, 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%*d", BIG_NUM, 42), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, IntPrecision) {
|
TEST(PrintfTest, IntPrecision) {
|
||||||
@ -267,24 +266,22 @@ TEST(PrintfTest, DynamicPrecision) {
|
|||||||
EXPECT_EQ("00042", test_sprintf("%.*d", 5, 42));
|
EXPECT_EQ("00042", test_sprintf("%.*d", 5, 42));
|
||||||
EXPECT_EQ("42", test_sprintf("%.*d", -5, 42));
|
EXPECT_EQ("42", test_sprintf("%.*d", -5, 42));
|
||||||
EXPECT_THROW_MSG(test_sprintf("%.*d", 5.0, 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%.*d", 5.0, 42), format_error,
|
||||||
"precision is not integer");
|
"precision is not integer");
|
||||||
EXPECT_THROW_MSG(test_sprintf("%.*d"), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%.*d"), format_error,
|
||||||
"argument index out of range");
|
"argument index out of range");
|
||||||
EXPECT_THROW_MSG(test_sprintf("%.*d", BIG_NUM, 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%.*d", BIG_NUM, 42), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
if (sizeof(long long) != sizeof(int)) {
|
if (sizeof(long long) != sizeof(int)) {
|
||||||
long long prec = static_cast<long long>(INT_MIN) - 1;
|
long long prec = static_cast<long long>(INT_MIN) - 1;
|
||||||
EXPECT_THROW_MSG(test_sprintf("%.*d", prec, 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%.*d", prec, 42), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
@ -295,7 +292,7 @@ SPECIALIZE_MAKE_SIGNED(unsigned long long, long long);
|
|||||||
|
|
||||||
// Test length format specifier ``length_spec``.
|
// Test length format specifier ``length_spec``.
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
void TestLength(const char *length_spec, U value) {
|
void TestLength(const char* length_spec, U value) {
|
||||||
long long signed_value = 0;
|
long long signed_value = 0;
|
||||||
unsigned long long unsigned_value = 0;
|
unsigned long long unsigned_value = 0;
|
||||||
// Apply integer promotion to the argument.
|
// Apply integer promotion to the argument.
|
||||||
@ -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);
|
||||||
@ -430,32 +426,32 @@ TEST(PrintfTest, Char) {
|
|||||||
EXPECT_PRINTF("x", "%c", 'x');
|
EXPECT_PRINTF("x", "%c", 'x');
|
||||||
int max = std::numeric_limits<int>::max();
|
int max = std::numeric_limits<int>::max();
|
||||||
EXPECT_PRINTF(fmt::format("{}", static_cast<char>(max)), "%c", max);
|
EXPECT_PRINTF(fmt::format("{}", static_cast<char>(max)), "%c", max);
|
||||||
//EXPECT_PRINTF("x", "%lc", L'x');
|
// EXPECT_PRINTF("x", "%lc", L'x');
|
||||||
EXPECT_PRINTF(L"x", L"%c", L'x');
|
EXPECT_PRINTF(L"x", L"%c", L'x');
|
||||||
EXPECT_PRINTF(fmt::format(L"{}", static_cast<wchar_t>(max)), L"%c", max);
|
EXPECT_PRINTF(fmt::format(L"{}", static_cast<wchar_t>(max)), L"%c", max);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, String) {
|
TEST(PrintfTest, String) {
|
||||||
EXPECT_PRINTF("abc", "%s", "abc");
|
EXPECT_PRINTF("abc", "%s", "abc");
|
||||||
const char *null_str = FMT_NULL;
|
const char* null_str = FMT_NULL;
|
||||||
EXPECT_PRINTF("(null)", "%s", null_str);
|
EXPECT_PRINTF("(null)", "%s", null_str);
|
||||||
EXPECT_PRINTF(" (null)", "%10s", null_str);
|
EXPECT_PRINTF(" (null)", "%10s", null_str);
|
||||||
EXPECT_PRINTF(L"abc", L"%s", L"abc");
|
EXPECT_PRINTF(L"abc", L"%s", L"abc");
|
||||||
const wchar_t *null_wstr = FMT_NULL;
|
const wchar_t* null_wstr = FMT_NULL;
|
||||||
EXPECT_PRINTF(L"(null)", L"%s", null_wstr);
|
EXPECT_PRINTF(L"(null)", L"%s", null_wstr);
|
||||||
EXPECT_PRINTF(L" (null)", L"%10s", null_wstr);
|
EXPECT_PRINTF(L" (null)", L"%10s", null_wstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, Pointer) {
|
TEST(PrintfTest, Pointer) {
|
||||||
int n;
|
int n;
|
||||||
void *p = &n;
|
void* p = &n;
|
||||||
EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
|
EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
|
||||||
p = FMT_NULL;
|
p = FMT_NULL;
|
||||||
EXPECT_PRINTF("(nil)", "%p", p);
|
EXPECT_PRINTF("(nil)", "%p", p);
|
||||||
EXPECT_PRINTF(" (nil)", "%10p", p);
|
EXPECT_PRINTF(" (nil)", "%10p", p);
|
||||||
const char *s = "test";
|
const char* s = "test";
|
||||||
EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s);
|
EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s);
|
||||||
const char *null_str = FMT_NULL;
|
const char* null_str = FMT_NULL;
|
||||||
EXPECT_PRINTF("(nil)", "%p", null_str);
|
EXPECT_PRINTF("(nil)", "%p", null_str);
|
||||||
|
|
||||||
p = &n;
|
p = &n;
|
||||||
@ -463,9 +459,9 @@ TEST(PrintfTest, Pointer) {
|
|||||||
p = FMT_NULL;
|
p = FMT_NULL;
|
||||||
EXPECT_PRINTF(L"(nil)", L"%p", p);
|
EXPECT_PRINTF(L"(nil)", L"%p", p);
|
||||||
EXPECT_PRINTF(L" (nil)", L"%10p", p);
|
EXPECT_PRINTF(L" (nil)", L"%10p", p);
|
||||||
const wchar_t *w = L"test";
|
const wchar_t* w = L"test";
|
||||||
EXPECT_PRINTF(fmt::format(L"{:p}", w), L"%p", w);
|
EXPECT_PRINTF(fmt::format(L"{:p}", w), L"%p", w);
|
||||||
const wchar_t *null_wstr = FMT_NULL;
|
const wchar_t* null_wstr = FMT_NULL;
|
||||||
EXPECT_PRINTF(L"(nil)", L"%p", null_wstr);
|
EXPECT_PRINTF(L"(nil)", L"%p", null_wstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,14 +471,12 @@ 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) {
|
||||||
const char *weekday = "Thursday";
|
const char* weekday = "Thursday";
|
||||||
const char *month = "August";
|
const char* month = "August";
|
||||||
int day = 21;
|
int day = 21;
|
||||||
EXPECT_WRITE(stdout, fmt::printf("%1$s, %3$d %2$s", weekday, month, day),
|
EXPECT_WRITE(stdout, fmt::printf("%1$s, %3$d %2$s", weekday, month, day),
|
||||||
"Thursday, 21 August");
|
"Thursday, 21 August");
|
||||||
@ -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")));
|
||||||
@ -520,7 +512,7 @@ TEST(PrintfTest, VPrintf) {
|
|||||||
EXPECT_WRITE(stdout, fmt::vfprintf(std::cout, "%d", args), "42");
|
EXPECT_WRITE(stdout, fmt::vfprintf(std::cout, "%d", args), "42");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template <typename... Args>
|
||||||
void check_format_string_regression(fmt::string_view s, const Args&... args) {
|
void check_format_string_regression(fmt::string_view s, const Args&... args) {
|
||||||
fmt::sprintf(s, args...);
|
fmt::sprintf(s, args...);
|
||||||
}
|
}
|
||||||
@ -530,40 +522,36 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, VSPrintfMakeWArgsExample) {
|
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
|
||||||
}
|
}
|
||||||
|
@ -13,13 +13,13 @@
|
|||||||
#if (__cplusplus > 201402L) || \
|
#if (__cplusplus > 201402L) || \
|
||||||
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
|
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
|
||||||
|
|
||||||
#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};
|
||||||
@ -45,15 +45,14 @@ TEST(RangesTest, FormatPair) {
|
|||||||
|
|
||||||
TEST(RangesTest, FormatTuple) {
|
TEST(RangesTest, FormatTuple) {
|
||||||
std::tuple<int64_t, float, std::string, char> tu1{42, 3.14159265358979f,
|
std::tuple<int64_t, float, std::string, char> tu1{42, 3.14159265358979f,
|
||||||
"this is tuple", 'i'};
|
"this is tuple", 'i'};
|
||||||
EXPECT_EQ("(42, 3.14159, \"this is tuple\", 'i')", fmt::format("{}", tu1));
|
EXPECT_EQ("(42, 3.14159, \"this is tuple\", 'i')", fmt::format("{}", tu1));
|
||||||
}
|
}
|
||||||
|
|
||||||
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>());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
class assertion_failure : public std::logic_error {
|
class assertion_failure : public std::logic_error {
|
||||||
public:
|
public:
|
||||||
explicit assertion_failure(const char *message) : std::logic_error(message) {}
|
explicit assertion_failure(const char* message) : std::logic_error(message) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FMT_ASSERT(condition, message) \
|
#define FMT_ASSERT(condition, message) \
|
||||||
|
@ -9,23 +9,23 @@
|
|||||||
#include "gtest.h"
|
#include "gtest.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# include <crtdbg.h>
|
# include <crtdbg.h>
|
||||||
#else
|
#else
|
||||||
# define _CrtSetReportFile(a, b)
|
# define _CrtSetReportFile(a, b)
|
||||||
# define _CrtSetReportMode(a, b)
|
# define _CrtSetReportMode(a, b)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char** argv) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Don't display any error dialogs. This also suppresses message boxes
|
// Don't display any error dialogs. This also suppresses message boxes
|
||||||
// on assertion failures in MinGW where _set_error_mode/CrtSetReportMode
|
// on assertion failures in MinGW where _set_error_mode/CrtSetReportMode
|
||||||
// doesn't help.
|
// doesn't help.
|
||||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
|
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
|
||||||
SEM_NOOPENFILEERRORBOX);
|
SEM_NOOPENFILEERRORBOX);
|
||||||
#endif
|
#endif
|
||||||
// Disable message boxes on assertion failures.
|
// Disable message boxes on assertion failures.
|
||||||
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
||||||
|
@ -6,17 +6,17 @@
|
|||||||
// For the license information refer to format.h.
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#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();
|
||||||
tm.tm_year = 116;
|
tm.tm_year = 116;
|
||||||
tm.tm_mon = 3;
|
tm.tm_mon = 3;
|
||||||
tm.tm_mday = 25;
|
tm.tm_mday = 25;
|
||||||
EXPECT_EQ("The date is 2016-04-25.",
|
EXPECT_EQ("The date is 2016-04-25.",
|
||||||
fmt::format("The date is {:%Y-%m-%d}.", tm));
|
fmt::format("The date is {:%Y-%m-%d}.", 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
void increment(char *s) {
|
void increment(char* s) {
|
||||||
for (int i = static_cast<int>(std::strlen(s)) - 1; i >= 0; --i) {
|
for (int i = static_cast<int>(std::strlen(s)) - 1; i >= 0; --i) {
|
||||||
if (s[i] != '9') {
|
if (s[i] != '9') {
|
||||||
++s[i];
|
++s[i];
|
||||||
@ -30,15 +30,14 @@ std::string get_system_error(int error_code) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *const FILE_CONTENT = "Don't panic!";
|
const char* const FILE_CONTENT = "Don't panic!";
|
||||||
|
|
||||||
fmt::buffered_file open_buffered_file(FILE **fp) {
|
fmt::buffered_file open_buffered_file(FILE** fp) {
|
||||||
fmt::file read_end, write_end;
|
fmt::file read_end, write_end;
|
||||||
fmt::file::pipe(read_end, write_end);
|
fmt::file::pipe(read_end, write_end);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
33
test/util.h
33
test/util.h
@ -11,16 +11,16 @@
|
|||||||
|
|
||||||
#include "fmt/posix.h"
|
#include "fmt/posix.h"
|
||||||
|
|
||||||
enum {BUFFER_SIZE = 256};
|
enum { BUFFER_SIZE = 256 };
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# define FMT_VSNPRINTF vsprintf_s
|
# define FMT_VSNPRINTF vsprintf_s
|
||||||
#else
|
#else
|
||||||
# define FMT_VSNPRINTF vsnprintf
|
# define FMT_VSNPRINTF vsnprintf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <std::size_t SIZE>
|
template <std::size_t SIZE>
|
||||||
void safe_sprintf(char (&buffer)[SIZE], const char *format, ...) {
|
void safe_sprintf(char (&buffer)[SIZE], const char* format, ...) {
|
||||||
std::va_list args;
|
std::va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
FMT_VSNPRINTF(buffer, SIZE, format, args);
|
FMT_VSNPRINTF(buffer, SIZE, format, args);
|
||||||
@ -28,19 +28,19 @@ void safe_sprintf(char (&buffer)[SIZE], const char *format, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Increment a number in a string.
|
// Increment a number in a string.
|
||||||
void increment(char *s);
|
void increment(char* s);
|
||||||
|
|
||||||
std::string get_system_error(int error_code);
|
std::string get_system_error(int error_code);
|
||||||
|
|
||||||
extern const char *const FILE_CONTENT;
|
extern const char* const FILE_CONTENT;
|
||||||
|
|
||||||
// Opens a buffered file for reading.
|
// Opens a buffered file for reading.
|
||||||
fmt::buffered_file open_buffered_file(FILE **fp = FMT_NULL);
|
fmt::buffered_file open_buffered_file(FILE** fp = FMT_NULL);
|
||||||
|
|
||||||
inline FILE *safe_fopen(const char *filename, const char *mode) {
|
inline FILE* safe_fopen(const char* filename, const char* mode) {
|
||||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
// Fix MSVC warning about "unsafe" fopen.
|
// Fix MSVC warning about "unsafe" fopen.
|
||||||
FILE *f = 0;
|
FILE* f = 0;
|
||||||
errno = fopen_s(&f, filename, mode);
|
errno = fopen_s(&f, filename, mode);
|
||||||
return f;
|
return f;
|
||||||
#else
|
#else
|
||||||
@ -48,34 +48,33 @@ 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_;
|
||||||
|
|
||||||
static const Char EMPTY[];
|
static const Char EMPTY[];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BasicTestString(const Char *value = EMPTY) : value_(value) {}
|
explicit BasicTestString(const Char* value = EMPTY) : value_(value) {}
|
||||||
|
|
||||||
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) {}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user