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.
|
||||
template <typename Char, typename Handler>
|
||||
FMT_CONSTEXPR const Char *parse_chrono_format(
|
||||
const Char *begin, const Char *end, Handler &&handler) {
|
||||
FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
|
||||
const Char* end,
|
||||
Handler&& handler) {
|
||||
auto ptr = begin;
|
||||
while (ptr != end) {
|
||||
auto c = *ptr;
|
||||
@ -38,11 +39,9 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
|
||||
++ptr;
|
||||
continue;
|
||||
}
|
||||
if (begin != ptr)
|
||||
handler.on_text(begin, ptr);
|
||||
if (begin != ptr) handler.on_text(begin, ptr);
|
||||
++ptr; // consume '%'
|
||||
if (ptr == end)
|
||||
throw format_error("invalid format");
|
||||
if (ptr == end) throw format_error("invalid format");
|
||||
c = *ptr++;
|
||||
switch (c) {
|
||||
case '%':
|
||||
@ -127,8 +126,7 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
|
||||
break;
|
||||
// Alternative representation:
|
||||
case 'E': {
|
||||
if (ptr == end)
|
||||
throw format_error("invalid format");
|
||||
if (ptr == end) throw format_error("invalid format");
|
||||
c = *ptr++;
|
||||
switch (c) {
|
||||
case 'c':
|
||||
@ -146,8 +144,7 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
|
||||
break;
|
||||
}
|
||||
case 'O':
|
||||
if (ptr == end)
|
||||
throw format_error("invalid format");
|
||||
if (ptr == end) throw format_error("invalid format");
|
||||
c = *ptr++;
|
||||
switch (c) {
|
||||
case 'w':
|
||||
@ -177,16 +174,14 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
|
||||
}
|
||||
begin = ptr;
|
||||
}
|
||||
if (begin != ptr)
|
||||
handler.on_text(begin, ptr);
|
||||
if (begin != ptr) handler.on_text(begin, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
struct chrono_format_checker {
|
||||
void report_no_date() { throw format_error("no date"); }
|
||||
|
||||
template <typename Char>
|
||||
void on_text(const Char *, const Char *) {}
|
||||
template <typename Char> void on_text(const Char*, const Char*) {}
|
||||
void on_abbr_weekday() { report_no_date(); }
|
||||
void on_full_weekday() { report_no_date(); }
|
||||
void on_dec0_weekday(numeric_system) { report_no_date(); }
|
||||
@ -210,15 +205,14 @@ struct chrono_format_checker {
|
||||
void on_tz_name() { report_no_date(); }
|
||||
};
|
||||
|
||||
template <typename Int>
|
||||
inline int to_int(Int value) {
|
||||
template <typename Int> inline int to_int(Int value) {
|
||||
FMT_ASSERT(value >= (std::numeric_limits<int>::min)() &&
|
||||
value <= (std::numeric_limits<int>::max)(), "invalid value");
|
||||
value <= (std::numeric_limits<int>::max)(),
|
||||
"invalid value");
|
||||
return static_cast<int>(value);
|
||||
}
|
||||
|
||||
template <typename FormatContext, typename OutputIt>
|
||||
struct chrono_formatter {
|
||||
template <typename FormatContext, typename OutputIt> struct chrono_formatter {
|
||||
FormatContext& context;
|
||||
OutputIt out;
|
||||
std::chrono::seconds s;
|
||||
@ -251,8 +245,7 @@ struct chrono_formatter {
|
||||
typedef typename int_traits<int>::main_type main_type;
|
||||
main_type n = to_unsigned(value);
|
||||
int num_digits = internal::count_digits(n);
|
||||
if (width > num_digits)
|
||||
out = std::fill_n(out, width - num_digits, '0');
|
||||
if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
|
||||
out = format_decimal<char_type>(out, n, num_digits);
|
||||
}
|
||||
|
||||
@ -286,24 +279,21 @@ struct chrono_formatter {
|
||||
void on_tz_name() {}
|
||||
|
||||
void on_24_hour(numeric_system ns) {
|
||||
if (ns == numeric_system::standard)
|
||||
return write(hour(), 2);
|
||||
if (ns == numeric_system::standard) return write(hour(), 2);
|
||||
auto time = tm();
|
||||
time.tm_hour = hour();
|
||||
format_localized(time, "%OH");
|
||||
}
|
||||
|
||||
void on_12_hour(numeric_system ns) {
|
||||
if (ns == numeric_system::standard)
|
||||
return write(hour12(), 2);
|
||||
if (ns == numeric_system::standard) return write(hour12(), 2);
|
||||
auto time = tm();
|
||||
time.tm_hour = hour();
|
||||
format_localized(time, "%OI");
|
||||
}
|
||||
|
||||
void on_minute(numeric_system ns) {
|
||||
if (ns == numeric_system::standard)
|
||||
return write(minute(), 2);
|
||||
if (ns == numeric_system::standard) return write(minute(), 2);
|
||||
auto time = tm();
|
||||
time.tm_min = minute();
|
||||
format_localized(time, "%OM");
|
||||
@ -382,8 +372,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||
basic_parse_context<Char>& context;
|
||||
basic_string_view<Char> format_str;
|
||||
|
||||
template <typename Id>
|
||||
FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
|
||||
template <typename Id> FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
|
||||
context.check_arg_id(arg_id);
|
||||
return arg_ref_type(arg_id);
|
||||
}
|
||||
@ -403,8 +392,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||
void on_align(alignment align) { f.spec.align_ = align; }
|
||||
void on_width(unsigned width) { f.spec.width_ = width; }
|
||||
|
||||
template <typename Id>
|
||||
void on_dynamic_width(Id arg_id) {
|
||||
template <typename Id> void on_dynamic_width(Id arg_id) {
|
||||
f.width_ref = make_arg_ref(arg_id);
|
||||
}
|
||||
};
|
||||
@ -421,14 +409,13 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||
if (begin == end) return begin;
|
||||
begin = internal::parse_width(begin, end, handler);
|
||||
end = parse_chrono_format(begin, end, internal::chrono_format_checker());
|
||||
format_str = basic_string_view<Char>(
|
||||
&*begin, internal::to_unsigned(end - begin));
|
||||
format_str =
|
||||
basic_string_view<Char>(&*begin, internal::to_unsigned(end - begin));
|
||||
return end;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const duration &d, FormatContext &ctx)
|
||||
-> decltype(ctx.out()) {
|
||||
auto format(const duration& d, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||
auto begin = format_str.begin(), end = format_str.end();
|
||||
// As a possible future optimization, we could avoid extra copying if width
|
||||
// is not specified.
|
||||
@ -449,8 +436,8 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||
f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s);
|
||||
parse_chrono_format(begin, end, f);
|
||||
}
|
||||
internal::handle_dynamic_spec<internal::width_checker>(
|
||||
spec.width_, width_ref, ctx);
|
||||
internal::handle_dynamic_spec<internal::width_checker>(spec.width_,
|
||||
width_ref, ctx);
|
||||
w.write(buf.data(), buf.size(), spec);
|
||||
return w.out();
|
||||
}
|
||||
|
@ -226,7 +226,8 @@ struct rgb {
|
||||
FMT_CONSTEXPR rgb(uint32_t hex)
|
||||
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {}
|
||||
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) {}
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
@ -237,19 +238,17 @@ namespace internal {
|
||||
|
||||
// color is a struct of either a rgb color or a terminal color.
|
||||
struct color_type {
|
||||
FMT_CONSTEXPR color_type() FMT_NOEXCEPT
|
||||
: is_rgb(), value{} {}
|
||||
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT
|
||||
: is_rgb(true), value{} {
|
||||
FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
|
||||
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
|
||||
value{} {
|
||||
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
||||
}
|
||||
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT
|
||||
: is_rgb(true), value{} {
|
||||
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16)
|
||||
| (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
||||
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} {
|
||||
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
|
||||
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
||||
}
|
||||
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT
|
||||
: is_rgb(), value{} {
|
||||
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
|
||||
value{} {
|
||||
value.term_color = static_cast<uint8_t>(term_color);
|
||||
}
|
||||
bool is_rgb;
|
||||
@ -264,7 +263,9 @@ struct color_type {
|
||||
class text_style {
|
||||
public:
|
||||
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) {
|
||||
if (!set_foreground_color) {
|
||||
@ -290,8 +291,8 @@ class text_style {
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR
|
||||
text_style operator|(text_style lhs, const text_style &rhs) {
|
||||
friend FMT_CONSTEXPR text_style operator|(text_style lhs,
|
||||
const text_style& rhs) {
|
||||
return lhs |= rhs;
|
||||
}
|
||||
|
||||
@ -319,8 +320,8 @@ class text_style {
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR
|
||||
text_style operator&(text_style lhs, const text_style &rhs) {
|
||||
friend FMT_CONSTEXPR text_style operator&(text_style lhs,
|
||||
const text_style& rhs) {
|
||||
return lhs &= rhs;
|
||||
}
|
||||
|
||||
@ -387,8 +388,7 @@ FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename Char>
|
||||
struct ansi_color_escape {
|
||||
template <typename Char> struct ansi_color_escape {
|
||||
FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
|
||||
const char* esc) FMT_NOEXCEPT {
|
||||
// If we have a terminal color, we need to output another escape code
|
||||
@ -398,8 +398,7 @@ struct ansi_color_escape {
|
||||
uint32_t value = text_color.value.term_color;
|
||||
// Background ASCII codes are the same as the foreground ones but with
|
||||
// 10 more.
|
||||
if (is_background)
|
||||
value += 10u;
|
||||
if (is_background) value += 10u;
|
||||
|
||||
std::size_t index = 0;
|
||||
buffer[index++] = static_cast<Char>('\x1b');
|
||||
@ -429,19 +428,15 @@ struct ansi_color_escape {
|
||||
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
|
||||
uint8_t em_codes[4] = {};
|
||||
uint8_t em_bits = static_cast<uint8_t>(em);
|
||||
if (em_bits & static_cast<uint8_t>(emphasis::bold))
|
||||
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::underline))
|
||||
em_codes[2] = 4;
|
||||
if (em_bits & static_cast<uint8_t>(emphasis::bold)) 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::underline)) em_codes[2] = 4;
|
||||
if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
|
||||
em_codes[3] = 9;
|
||||
|
||||
std::size_t index = 0;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (!em_codes[i])
|
||||
continue;
|
||||
if (!em_codes[i]) continue;
|
||||
buffer[index++] = static_cast<Char>('\x1b');
|
||||
buffer[index++] = static_cast<Char>('[');
|
||||
buffer[index++] = static_cast<Char>('0' + em_codes[i]);
|
||||
@ -451,9 +446,7 @@ struct ansi_color_escape {
|
||||
}
|
||||
FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
|
||||
|
||||
FMT_CONSTEXPR const Char * begin() const FMT_NOEXCEPT {
|
||||
return buffer;
|
||||
}
|
||||
FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
|
||||
FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT {
|
||||
return buffer + std::strlen(buffer);
|
||||
}
|
||||
@ -471,20 +464,19 @@ private:
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR ansi_color_escape<Char>
|
||||
make_foreground_color(internal::color_type foreground) FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
|
||||
internal::color_type foreground) FMT_NOEXCEPT {
|
||||
return ansi_color_escape<Char>(foreground, internal::data::FOREGROUND_COLOR);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR ansi_color_escape<Char>
|
||||
make_background_color(internal::color_type background) FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
|
||||
internal::color_type background) FMT_NOEXCEPT {
|
||||
return ansi_color_escape<Char>(background, internal::data::BACKGROUND_COLOR);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR ansi_color_escape<Char>
|
||||
make_emphasis(emphasis em) FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT {
|
||||
return ansi_color_escape<Char>(em);
|
||||
}
|
||||
|
||||
@ -498,13 +490,11 @@ inline void fputs<wchar_t>(const wchar_t *chars, FILE *stream) FMT_NOEXCEPT {
|
||||
std::fputws(chars, stream);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void reset_color(FILE *stream) FMT_NOEXCEPT {
|
||||
template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
|
||||
fputs(internal::data::RESET_COLOR, stream);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void reset_color<wchar_t>(FILE *stream) FMT_NOEXCEPT {
|
||||
template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
|
||||
fputs(internal::data::WRESET_COLOR, stream);
|
||||
}
|
||||
|
||||
@ -519,10 +509,8 @@ inline void reset_color(basic_memory_buffer<Char>& buffer) FMT_NOEXCEPT {
|
||||
// which is needed because or else
|
||||
// fmt::print(stderr, fmt::emphasis::bold, "");
|
||||
// would take stderr (a std::FILE *) as the format string.
|
||||
template <>
|
||||
struct is_string<std::FILE *> : std::false_type {};
|
||||
template <>
|
||||
struct is_string<const std::FILE *> : std::false_type {};
|
||||
template <> struct is_string<std::FILE*> : std::false_type {};
|
||||
template <> struct is_string<const std::FILE*> : std::false_type {};
|
||||
|
||||
template <typename Char>
|
||||
std::basic_string<Char> vformat(
|
||||
@ -532,8 +520,7 @@ std::basic_string<Char> vformat(
|
||||
bool has_style = false;
|
||||
if (ts.has_emphasis()) {
|
||||
has_style = true;
|
||||
ansi_color_escape<Char> escape =
|
||||
make_emphasis<Char>(ts.get_emphasis());
|
||||
ansi_color_escape<Char> escape = make_emphasis<Char>(ts.get_emphasis());
|
||||
buffer.append(escape.begin(), escape.end());
|
||||
}
|
||||
if (ts.has_foreground()) {
|
||||
@ -556,15 +543,13 @@ std::basic_string<Char> vformat(
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
template <
|
||||
typename S, typename Char = typename internal::char_t<S>::type>
|
||||
template <typename S, typename Char = typename internal::char_t<S>::type>
|
||||
void vprint(std::FILE* f, const text_style& ts, const S& format,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
bool has_style = false;
|
||||
if (ts.has_emphasis()) {
|
||||
has_style = true;
|
||||
internal::fputs<Char>(
|
||||
internal::make_emphasis<Char>(ts.get_emphasis()), f);
|
||||
internal::fputs<Char>(internal::make_emphasis<Char>(ts.get_emphasis()), f);
|
||||
}
|
||||
if (ts.has_foreground()) {
|
||||
has_style = true;
|
||||
@ -609,16 +594,13 @@ typename std::enable_if<internal::is_string<String>::value>::type print(
|
||||
*/
|
||||
template <typename String, typename... Args>
|
||||
typename std::enable_if<internal::is_string<String>::value>::type print(
|
||||
const text_style &ts, const String &format_str,
|
||||
const Args &... args) {
|
||||
const text_style& ts, const String& format_str, const Args&... args) {
|
||||
return print(stdout, ts, format_str, args...);
|
||||
}
|
||||
|
||||
|
||||
template <typename S, typename Char = FMT_CHAR(S)>
|
||||
inline std::basic_string<Char> vformat(
|
||||
const text_style &ts,
|
||||
const S &format_str,
|
||||
const text_style& ts, const S& format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
return internal::vformat(ts, to_string_view(format_str), args);
|
||||
}
|
||||
@ -636,8 +618,9 @@ inline std::basic_string<Char> vformat(
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args>
|
||||
inline std::basic_string<FMT_CHAR(S)> format(
|
||||
const text_style &ts, const S &format_str, const Args &... args) {
|
||||
inline std::basic_string<FMT_CHAR(S)> format(const text_style& ts,
|
||||
const S& format_str,
|
||||
const Args&... args) {
|
||||
return internal::vformat(
|
||||
ts, to_string_view(format_str),
|
||||
*internal::checked_args<S, Args...>(format_str, args...));
|
||||
|
@ -89,8 +89,8 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if FMT_HAS_FEATURE(cxx_explicit_conversions) || \
|
||||
FMT_GCC_VERSION >= 405 || FMT_MSC_VER >= 1800
|
||||
#if FMT_HAS_FEATURE(cxx_explicit_conversions) || FMT_GCC_VERSION >= 405 || \
|
||||
FMT_MSC_VER >= 1800
|
||||
# define FMT_USE_EXPLICIT 1
|
||||
# define FMT_EXPLICIT explicit
|
||||
#else
|
||||
@ -147,12 +147,19 @@
|
||||
# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
|
||||
FMT_MSC_VER >= 1900
|
||||
# define FMT_INLINE_NAMESPACE inline namespace
|
||||
# define FMT_END_NAMESPACE }}
|
||||
# define FMT_END_NAMESPACE \
|
||||
} \
|
||||
}
|
||||
# else
|
||||
# define FMT_INLINE_NAMESPACE namespace
|
||||
# define FMT_END_NAMESPACE } using namespace v5; }
|
||||
# define FMT_END_NAMESPACE \
|
||||
} \
|
||||
using namespace v5; \
|
||||
}
|
||||
# endif
|
||||
# define FMT_BEGIN_NAMESPACE namespace fmt { FMT_INLINE_NAMESPACE v5 {
|
||||
# define FMT_BEGIN_NAMESPACE \
|
||||
namespace fmt { \
|
||||
FMT_INLINE_NAMESPACE v5 {
|
||||
#endif
|
||||
|
||||
#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
|
||||
@ -193,14 +200,12 @@ namespace internal {
|
||||
template <typename T>
|
||||
typename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT;
|
||||
|
||||
template <typename>
|
||||
struct result_of;
|
||||
template <typename> struct result_of;
|
||||
|
||||
template <typename F, typename... Args>
|
||||
struct result_of<F(Args...)> {
|
||||
template <typename F, typename... Args> struct result_of<F(Args...)> {
|
||||
// A workaround for gcc 4.4 that doesn't allow F to be a reference.
|
||||
typedef typename std::result_of<
|
||||
typename std::remove_reference<F>::type(Args...)>::type type;
|
||||
typedef typename std::result_of<typename std::remove_reference<F>::type(
|
||||
Args...)>::type type;
|
||||
};
|
||||
|
||||
// Casts nonnegative integer to unsigned.
|
||||
@ -211,8 +216,7 @@ FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
|
||||
}
|
||||
|
||||
/** A contiguous memory buffer with an optional growing ability. */
|
||||
template <typename T>
|
||||
class basic_buffer {
|
||||
template <typename T> class basic_buffer {
|
||||
private:
|
||||
basic_buffer(const basic_buffer&) = delete;
|
||||
void operator=(const basic_buffer&) = delete;
|
||||
@ -225,8 +229,10 @@ class basic_buffer {
|
||||
// Don't initialize ptr_ since it is not accessed to save a few cycles.
|
||||
basic_buffer(std::size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {}
|
||||
|
||||
basic_buffer(T *p = FMT_NULL, std::size_t sz = 0, std::size_t cap = 0)
|
||||
FMT_NOEXCEPT: ptr_(p), size_(sz), capacity_(cap) {}
|
||||
basic_buffer(T* p = FMT_NULL, std::size_t sz = 0,
|
||||
std::size_t cap = 0) FMT_NOEXCEPT : ptr_(p),
|
||||
size_(sz),
|
||||
capacity_(cap) {}
|
||||
|
||||
/** Sets the buffer data and capacity. */
|
||||
void set(T* buf_data, std::size_t buf_capacity) FMT_NOEXCEPT {
|
||||
@ -271,8 +277,7 @@ class basic_buffer {
|
||||
|
||||
/** Reserves space to store at least *capacity* elements. */
|
||||
void reserve(std::size_t new_capacity) {
|
||||
if (new_capacity > capacity_)
|
||||
grow(new_capacity);
|
||||
if (new_capacity > capacity_) grow(new_capacity);
|
||||
}
|
||||
|
||||
void push_back(const T& value) {
|
||||
@ -281,8 +286,7 @@ class basic_buffer {
|
||||
}
|
||||
|
||||
/** Appends data to the end of the buffer. */
|
||||
template <typename U>
|
||||
void append(const U *begin, const U *end);
|
||||
template <typename U> void append(const U* begin, const U* end);
|
||||
|
||||
T& operator[](std::size_t index) { return ptr_[index]; }
|
||||
const T& operator[](std::size_t index) const { return ptr_[index]; }
|
||||
@ -327,13 +331,11 @@ struct error_handler {
|
||||
FMT_API void on_error(const char* message);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct no_formatter_error : std::false_type {};
|
||||
template <typename T> struct no_formatter_error : std::false_type {};
|
||||
} // namespace internal
|
||||
|
||||
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 405
|
||||
template <typename... T>
|
||||
struct is_constructible: std::false_type {};
|
||||
template <typename... T> struct is_constructible : std::false_type {};
|
||||
#else
|
||||
template <typename... T>
|
||||
struct is_constructible : std::is_constructible<T...> {};
|
||||
@ -346,8 +348,7 @@ struct is_constructible : std::is_constructible<T...> {};
|
||||
compiled with a different ``-std`` option than the client code (which is not
|
||||
recommended).
|
||||
*/
|
||||
template <typename Char>
|
||||
class basic_string_view {
|
||||
template <typename Char> class basic_string_view {
|
||||
private:
|
||||
const Char* data_;
|
||||
size_t size_;
|
||||
@ -360,7 +361,8 @@ class basic_string_view {
|
||||
|
||||
/** Constructs a string reference object from a C string and a size. */
|
||||
FMT_CONSTEXPR basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT
|
||||
: data_(s), size_(count) {}
|
||||
: data_(s),
|
||||
size_(count) {}
|
||||
|
||||
/**
|
||||
\rst
|
||||
@ -373,13 +375,14 @@ class basic_string_view {
|
||||
|
||||
/** Constructs a string reference from a ``std::basic_string`` object. */
|
||||
template <typename Alloc>
|
||||
FMT_CONSTEXPR basic_string_view(
|
||||
const std::basic_string<Char, Alloc> &s) FMT_NOEXCEPT
|
||||
: data_(s.data()), size_(s.size()) {}
|
||||
FMT_CONSTEXPR basic_string_view(const std::basic_string<Char, Alloc>& s)
|
||||
FMT_NOEXCEPT : data_(s.data()),
|
||||
size_(s.size()) {}
|
||||
|
||||
#ifdef FMT_STRING_VIEW
|
||||
FMT_CONSTEXPR basic_string_view(FMT_STRING_VIEW<Char> s) FMT_NOEXCEPT
|
||||
: data_(s.data()), size_(s.size()) {}
|
||||
: data_(s.data()),
|
||||
size_(s.size()) {}
|
||||
#endif
|
||||
|
||||
/** Returns a pointer to the string data. */
|
||||
@ -451,22 +454,26 @@ typedef basic_string_view<wchar_t> wstring_view;
|
||||
\endrst
|
||||
*/
|
||||
template <typename Char>
|
||||
inline basic_string_view<Char>
|
||||
to_string_view(basic_string_view<Char> s) { return s; }
|
||||
inline basic_string_view<Char> to_string_view(basic_string_view<Char> s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename Char, typename Traits, typename Allocator>
|
||||
inline basic_string_view<Char>
|
||||
to_string_view(const std::basic_string<Char, Traits, Allocator> &s) {
|
||||
inline basic_string_view<Char> to_string_view(
|
||||
const std::basic_string<Char, Traits, Allocator>& s) {
|
||||
return {s.data(), s.size()};
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline basic_string_view<Char> to_string_view(const Char *s) { return s; }
|
||||
inline basic_string_view<Char> to_string_view(const Char* s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef FMT_STRING_VIEW
|
||||
template <typename Char>
|
||||
inline basic_string_view<Char>
|
||||
to_string_view(FMT_STRING_VIEW<Char> s) { return s; }
|
||||
inline basic_string_view<Char> to_string_view(FMT_STRING_VIEW<Char> s) {
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
// A base class for compile-time strings. It is defined in the fmt namespace to
|
||||
@ -476,22 +483,22 @@ struct compile_string {};
|
||||
template <typename S>
|
||||
struct is_compile_string : std::is_base_of<compile_string, S> {};
|
||||
|
||||
template <
|
||||
typename S,
|
||||
typename Enable = typename std::enable_if<is_compile_string<S>::value>::type>
|
||||
FMT_CONSTEXPR basic_string_view<typename S::char_type>
|
||||
to_string_view(const S &s) { return s; }
|
||||
template <typename S, typename Enable = typename std::enable_if<
|
||||
is_compile_string<S>::value>::type>
|
||||
FMT_CONSTEXPR basic_string_view<typename S::char_type> to_string_view(
|
||||
const S& s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
class basic_format_arg;
|
||||
template <typename Context> class basic_format_arg;
|
||||
|
||||
template <typename Context>
|
||||
class basic_format_args;
|
||||
template <typename Context> class basic_format_args;
|
||||
|
||||
// A formatter for objects of type T.
|
||||
template <typename T, typename Char = char, typename Enable = void>
|
||||
struct formatter {
|
||||
static_assert(internal::no_formatter_error<T>::value,
|
||||
static_assert(
|
||||
internal::no_formatter_error<T>::value,
|
||||
"don't know how to format the type, include fmt/ostream.h if it provides "
|
||||
"an operator<< that should be used");
|
||||
|
||||
@ -503,40 +510,54 @@ struct formatter {
|
||||
};
|
||||
|
||||
template <typename T, typename Char, typename Enable = void>
|
||||
struct convert_to_int: std::integral_constant<
|
||||
bool, !std::is_arithmetic<T>::value && std::is_convertible<T, int>::value> {};
|
||||
struct convert_to_int
|
||||
: std::integral_constant<bool, !std::is_arithmetic<T>::value &&
|
||||
std::is_convertible<T, int>::value> {};
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct dummy_string_view { typedef void char_type; };
|
||||
struct dummy_string_view {
|
||||
typedef void char_type;
|
||||
};
|
||||
dummy_string_view to_string_view(...);
|
||||
using fmt::v5::to_string_view;
|
||||
|
||||
// Specifies whether S is a string type convertible to fmt::basic_string_view.
|
||||
template <typename S>
|
||||
struct is_string : std::integral_constant<bool, !std::is_same<
|
||||
dummy_string_view, decltype(to_string_view(declval<S>()))>::value> {};
|
||||
struct is_string
|
||||
: std::integral_constant<
|
||||
bool, !std::is_same<dummy_string_view,
|
||||
decltype(to_string_view(declval<S>()))>::value> {
|
||||
};
|
||||
|
||||
template <typename S>
|
||||
struct char_t {
|
||||
template <typename S> struct char_t {
|
||||
typedef decltype(to_string_view(declval<S>())) result;
|
||||
typedef typename result::char_type type;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct named_arg_base;
|
||||
template <typename Char> struct named_arg_base;
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct named_arg;
|
||||
template <typename T, typename Char> struct named_arg;
|
||||
|
||||
enum type {
|
||||
none_type, named_arg_type,
|
||||
none_type,
|
||||
named_arg_type,
|
||||
// Integer types should go first,
|
||||
int_type, uint_type, long_long_type, ulong_long_type, bool_type, char_type,
|
||||
int_type,
|
||||
uint_type,
|
||||
long_long_type,
|
||||
ulong_long_type,
|
||||
bool_type,
|
||||
char_type,
|
||||
last_integer_type = char_type,
|
||||
// followed by floating-point types.
|
||||
double_type, long_double_type, last_numeric_type = long_double_type,
|
||||
cstring_type, string_type, pointer_type, custom_type
|
||||
double_type,
|
||||
long_double_type,
|
||||
last_numeric_type = long_double_type,
|
||||
cstring_type,
|
||||
string_type,
|
||||
pointer_type,
|
||||
custom_type
|
||||
};
|
||||
|
||||
FMT_CONSTEXPR bool is_integral(type t) {
|
||||
@ -549,21 +570,18 @@ FMT_CONSTEXPR bool is_arithmetic(type t) {
|
||||
return t > internal::none_type && t <= internal::last_numeric_type;
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
struct string_value {
|
||||
template <typename Char> struct string_value {
|
||||
const Char* value;
|
||||
std::size_t size;
|
||||
};
|
||||
|
||||
template <typename Context>
|
||||
struct custom_value {
|
||||
template <typename Context> struct custom_value {
|
||||
const void* value;
|
||||
void (*format)(const void* arg, Context& ctx);
|
||||
};
|
||||
|
||||
// A formatting argument value.
|
||||
template <typename Context>
|
||||
class value {
|
||||
template <typename Context> class value {
|
||||
public:
|
||||
typedef typename Context::char_type char_type;
|
||||
|
||||
@ -604,8 +622,7 @@ class value {
|
||||
}
|
||||
value(const void* val) { pointer = val; }
|
||||
|
||||
template <typename T>
|
||||
explicit value(const T &val) {
|
||||
template <typename T> explicit value(const T& val) {
|
||||
custom.value = &val;
|
||||
custom.format = &format_custom_arg<T>;
|
||||
}
|
||||
@ -629,8 +646,7 @@ class value {
|
||||
};
|
||||
|
||||
// Value initializer used to delay conversion to value and reduce memory churn.
|
||||
template <typename Context, typename T, type TYPE>
|
||||
struct init {
|
||||
template <typename Context, typename T, type TYPE> struct init {
|
||||
T val;
|
||||
static const type type_tag = TYPE;
|
||||
|
||||
@ -649,7 +665,9 @@ FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value);
|
||||
|
||||
#define FMT_MAKE_VALUE_SAME(TAG, Type) \
|
||||
template <typename C> \
|
||||
FMT_CONSTEXPR init<C, Type, TAG> make_value(Type val) { return val; }
|
||||
FMT_CONSTEXPR init<C, Type, TAG> make_value(Type val) { \
|
||||
return val; \
|
||||
}
|
||||
|
||||
FMT_MAKE_VALUE(bool_type, bool, int)
|
||||
FMT_MAKE_VALUE(int_type, short, int)
|
||||
@ -661,12 +679,12 @@ FMT_MAKE_VALUE_SAME(uint_type, unsigned)
|
||||
// either to int or to long long depending on its size.
|
||||
typedef std::conditional<sizeof(long) == sizeof(int), int, long long>::type
|
||||
long_type;
|
||||
FMT_MAKE_VALUE(
|
||||
(sizeof(long) == sizeof(int) ? int_type : long_long_type), long, long_type)
|
||||
typedef std::conditional<sizeof(unsigned long) == sizeof(unsigned),
|
||||
unsigned, unsigned long long>::type ulong_type;
|
||||
FMT_MAKE_VALUE(
|
||||
(sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type),
|
||||
FMT_MAKE_VALUE((sizeof(long) == sizeof(int) ? int_type : long_long_type), long,
|
||||
long_type)
|
||||
typedef std::conditional<sizeof(unsigned long) == sizeof(unsigned), unsigned,
|
||||
unsigned long long>::type ulong_type;
|
||||
FMT_MAKE_VALUE((sizeof(unsigned long) == sizeof(unsigned) ? uint_type
|
||||
: ulong_long_type),
|
||||
unsigned long, ulong_type)
|
||||
|
||||
FMT_MAKE_VALUE_SAME(long_long_type, long long)
|
||||
@ -676,14 +694,20 @@ FMT_MAKE_VALUE(uint_type, unsigned char, unsigned)
|
||||
|
||||
// This doesn't use FMT_MAKE_VALUE because of ambiguity in gcc 4.4.
|
||||
template <typename C, typename Char>
|
||||
FMT_CONSTEXPR typename std::enable_if<
|
||||
std::is_same<typename C::char_type, Char>::value,
|
||||
init<C, int, char_type>>::type make_value(Char val) { return val; }
|
||||
FMT_CONSTEXPR
|
||||
typename std::enable_if<std::is_same<typename C::char_type, Char>::value,
|
||||
init<C, int, char_type>>::type
|
||||
make_value(Char val) {
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
FMT_CONSTEXPR typename std::enable_if<
|
||||
!std::is_same<typename C::char_type, char>::value,
|
||||
init<C, int, char_type>>::type make_value(char val) { return val; }
|
||||
FMT_CONSTEXPR
|
||||
typename std::enable_if<!std::is_same<typename C::char_type, char>::value,
|
||||
init<C, int, char_type>>::type
|
||||
make_value(char val) {
|
||||
return val;
|
||||
}
|
||||
|
||||
FMT_MAKE_VALUE(double_type, float, double)
|
||||
FMT_MAKE_VALUE_SAME(double_type, double)
|
||||
@ -724,17 +748,22 @@ typename std::enable_if<!std::is_same<T, typename C::char_type>::value>::type
|
||||
}
|
||||
|
||||
template <typename C, typename T>
|
||||
inline typename std::enable_if<
|
||||
std::is_enum<T>::value && convert_to_int<T, typename C::char_type>::value,
|
||||
inline
|
||||
typename std::enable_if<std::is_enum<T>::value &&
|
||||
convert_to_int<T, typename C::char_type>::value,
|
||||
init<C, int, int_type>>::type
|
||||
make_value(const T &val) { return static_cast<int>(val); }
|
||||
make_value(const T& val) {
|
||||
return static_cast<int>(val);
|
||||
}
|
||||
|
||||
template <typename C, typename T, typename Char = typename C::char_type>
|
||||
inline typename std::enable_if<
|
||||
is_constructible<basic_string_view<Char>, T>::value &&
|
||||
!internal::is_string<T>::value,
|
||||
init<C, basic_string_view<Char>, string_type>>::type
|
||||
make_value(const T &val) { return basic_string_view<Char>(val); }
|
||||
make_value(const T& val) {
|
||||
return basic_string_view<Char>(val);
|
||||
}
|
||||
|
||||
template <typename C, typename T, typename Char = typename C::char_type>
|
||||
inline typename std::enable_if<
|
||||
@ -745,11 +774,13 @@ inline typename std::enable_if<
|
||||
// Implicit conversion to std::string is not handled here because it's
|
||||
// unsafe: https://github.com/fmtlib/fmt/issues/729
|
||||
init<C, const T&, custom_type>>::type
|
||||
make_value(const T &val) { return val; }
|
||||
make_value(const T& val) {
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename C, typename T>
|
||||
init<C, const void*, named_arg_type>
|
||||
make_value(const named_arg<T, typename C::char_type> &val) {
|
||||
init<C, const void*, named_arg_type> make_value(
|
||||
const named_arg<T, typename C::char_type>& val) {
|
||||
basic_format_arg<C> arg = make_arg<C>(val.value);
|
||||
std::memcpy(val.data, &arg, sizeof(arg));
|
||||
return static_cast<const void*>(&val);
|
||||
@ -761,8 +792,8 @@ FMT_CONSTEXPR11 typename std::enable_if<
|
||||
init<C, basic_string_view<typename C::char_type>, string_type>>::type
|
||||
make_value(const S& val) {
|
||||
// Handle adapted strings.
|
||||
static_assert(std::is_same<
|
||||
typename C::char_type, typename internal::char_t<S>::type>::value,
|
||||
static_assert(std::is_same<typename C::char_type,
|
||||
typename internal::char_t<S>::type>::value,
|
||||
"mismatch between char-types of context and argument");
|
||||
return to_string_view(val);
|
||||
}
|
||||
@ -771,21 +802,19 @@ FMT_CONSTEXPR11 typename std::enable_if<
|
||||
enum { max_packed_args = 15 };
|
||||
enum : unsigned long long { is_unpacked_bit = 1ull << 63 };
|
||||
|
||||
template <typename Context>
|
||||
class arg_map;
|
||||
template <typename Context> class arg_map;
|
||||
} // namespace internal
|
||||
|
||||
// A formatting argument. It is a trivially copyable/constructible type to
|
||||
// allow storage in basic_memory_buffer.
|
||||
template <typename Context>
|
||||
class basic_format_arg {
|
||||
template <typename Context> class basic_format_arg {
|
||||
private:
|
||||
internal::value<Context> value_;
|
||||
internal::type type_;
|
||||
|
||||
template <typename ContextType, typename T>
|
||||
friend FMT_CONSTEXPR basic_format_arg<ContextType>
|
||||
internal::make_arg(const T &value);
|
||||
friend FMT_CONSTEXPR basic_format_arg<ContextType> internal::make_arg(
|
||||
const T& value);
|
||||
|
||||
template <typename Visitor, typename Ctx>
|
||||
friend FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
|
||||
@ -829,8 +858,8 @@ struct monostate {};
|
||||
\endrst
|
||||
*/
|
||||
template <typename Visitor, typename Context>
|
||||
FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
|
||||
visit_format_arg(Visitor &&vis, const basic_format_arg<Context> &arg) {
|
||||
FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type visit_format_arg(
|
||||
Visitor&& vis, const basic_format_arg<Context>& arg) {
|
||||
typedef typename Context::char_type char_type;
|
||||
switch (arg.type_) {
|
||||
case internal::none_type:
|
||||
@ -857,8 +886,8 @@ FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
|
||||
case internal::cstring_type:
|
||||
return vis(arg.value_.string.value);
|
||||
case internal::string_type:
|
||||
return vis(basic_string_view<char_type>(
|
||||
arg.value_.string.value, arg.value_.string.size));
|
||||
return vis(basic_string_view<char_type>(arg.value_.string.value,
|
||||
arg.value_.string.size));
|
||||
case internal::pointer_type:
|
||||
return vis(arg.value_.pointer);
|
||||
case internal::custom_type:
|
||||
@ -869,8 +898,8 @@ FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
|
||||
|
||||
// DEPRECATED!
|
||||
template <typename Visitor, typename Context>
|
||||
FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
|
||||
visit(Visitor &&vis, const basic_format_arg<Context> &arg) {
|
||||
FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type visit(
|
||||
Visitor&& vis, const basic_format_arg<Context>& arg) {
|
||||
return visit_format_arg(std::forward<Visitor>(vis), arg);
|
||||
}
|
||||
|
||||
@ -886,8 +915,8 @@ class basic_parse_context : private ErrorHandler {
|
||||
typedef Char char_type;
|
||||
typedef typename basic_string_view<Char>::iterator iterator;
|
||||
|
||||
explicit FMT_CONSTEXPR basic_parse_context(
|
||||
basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler())
|
||||
explicit FMT_CONSTEXPR basic_parse_context(basic_string_view<Char> format_str,
|
||||
ErrorHandler eh = ErrorHandler())
|
||||
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}
|
||||
|
||||
// Returns an iterator to the beginning of the format string range being
|
||||
@ -934,8 +963,7 @@ typedef basic_parse_context<wchar_t> wparse_context;
|
||||
|
||||
namespace internal {
|
||||
// A map from argument names to their values for named arguments.
|
||||
template <typename Context>
|
||||
class arg_map {
|
||||
template <typename Context> class arg_map {
|
||||
private:
|
||||
arg_map(const arg_map&) = delete;
|
||||
void operator=(const arg_map&) = delete;
|
||||
@ -964,8 +992,7 @@ class arg_map {
|
||||
basic_format_arg<Context> find(basic_string_view<char_type> name) const {
|
||||
// The list is unsorted, so just return the first matching name.
|
||||
for (entry *it = map_, *end = map_ + size_; it != end; ++it) {
|
||||
if (it->name == name)
|
||||
return it->arg;
|
||||
if (it->name == name) return it->arg;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@ -980,11 +1007,9 @@ class locale_ref {
|
||||
public:
|
||||
locale_ref() : locale_(FMT_NULL) {}
|
||||
|
||||
template <typename Locale>
|
||||
explicit locale_ref(const Locale &loc);
|
||||
template <typename Locale> explicit locale_ref(const Locale& loc);
|
||||
|
||||
template <typename Locale>
|
||||
Locale get() const;
|
||||
template <typename Locale> Locale get() const;
|
||||
};
|
||||
|
||||
template <typename OutputIt, typename Context, typename Char>
|
||||
@ -1010,16 +1035,15 @@ class context_base {
|
||||
// Returns the argument with specified index.
|
||||
format_arg do_get_arg(unsigned arg_id) {
|
||||
format_arg arg = args_.get(arg_id);
|
||||
if (!arg)
|
||||
parse_context_.on_error("argument index out of range");
|
||||
if (!arg) parse_context_.on_error("argument index out of range");
|
||||
return arg;
|
||||
}
|
||||
|
||||
// Checks if manual indexing is used and returns the argument with
|
||||
// specified index.
|
||||
format_arg get_arg(unsigned arg_id) {
|
||||
return this->parse_context().check_arg_id(arg_id) ?
|
||||
this->do_get_arg(arg_id) : format_arg();
|
||||
return this->parse_context().check_arg_id(arg_id) ? this->do_get_arg(arg_id)
|
||||
: format_arg();
|
||||
}
|
||||
|
||||
public:
|
||||
@ -1043,15 +1067,15 @@ class context_base {
|
||||
locale_ref locale() { return loc_; }
|
||||
};
|
||||
|
||||
template <typename Context, typename T>
|
||||
struct get_type {
|
||||
typedef decltype(make_value<Context>(
|
||||
declval<typename std::decay<T>::type&>())) value_type;
|
||||
template <typename Context, typename T> struct get_type {
|
||||
typedef decltype(
|
||||
make_value<Context>(declval<typename std::decay<T>::type&>())) value_type;
|
||||
static const type value = value_type::type_tag;
|
||||
};
|
||||
|
||||
template <typename Context>
|
||||
FMT_CONSTEXPR11 unsigned long long get_types() { return 0; }
|
||||
template <typename Context> FMT_CONSTEXPR11 unsigned long long get_types() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename Context, typename Arg, typename... Args>
|
||||
FMT_CONSTEXPR11 unsigned long long get_types() {
|
||||
@ -1067,8 +1091,8 @@ FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value) {
|
||||
}
|
||||
|
||||
template <bool IS_PACKED, typename Context, typename T>
|
||||
inline typename std::enable_if<IS_PACKED, value<Context>>::type
|
||||
make_arg(const T &value) {
|
||||
inline typename std::enable_if<IS_PACKED, value<Context>>::type make_arg(
|
||||
const T& value) {
|
||||
return make_value<Context>(value);
|
||||
}
|
||||
|
||||
@ -1081,16 +1105,17 @@ inline typename std::enable_if<!IS_PACKED, basic_format_arg<Context>>::type
|
||||
|
||||
// Formatting context.
|
||||
template <typename OutputIt, typename Char>
|
||||
class basic_format_context :
|
||||
public internal::context_base<
|
||||
class basic_format_context
|
||||
: public internal::context_base<
|
||||
OutputIt, basic_format_context<OutputIt, Char>, Char> {
|
||||
public:
|
||||
/** The character type for the output. */
|
||||
typedef Char char_type;
|
||||
|
||||
// using formatter_type = formatter<T, char_type>;
|
||||
template <typename T>
|
||||
struct formatter_type { typedef formatter<T, char_type> type; };
|
||||
template <typename T> struct formatter_type {
|
||||
typedef formatter<T, char_type> type;
|
||||
};
|
||||
|
||||
private:
|
||||
internal::arg_map<basic_format_context> map_;
|
||||
@ -1124,10 +1149,10 @@ class basic_format_context :
|
||||
format_arg get_arg(basic_string_view<char_type> name);
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct buffer_context {
|
||||
template <typename Char> struct buffer_context {
|
||||
typedef basic_format_context<
|
||||
std::back_insert_iterator<internal::basic_buffer<Char>>, Char> type;
|
||||
std::back_insert_iterator<internal::basic_buffer<Char>>, Char>
|
||||
type;
|
||||
};
|
||||
typedef buffer_context<char>::type format_context;
|
||||
typedef buffer_context<wchar_t>::type wformat_context;
|
||||
@ -1139,16 +1164,15 @@ typedef buffer_context<wchar_t>::type wformat_context;
|
||||
such as `~fmt::vformat`.
|
||||
\endrst
|
||||
*/
|
||||
template <typename Context, typename ...Args>
|
||||
class format_arg_store {
|
||||
template <typename Context, typename... Args> class format_arg_store {
|
||||
private:
|
||||
static const size_t NUM_ARGS = sizeof...(Args);
|
||||
|
||||
// Packed is a macro on MinGW so use IS_PACKED instead.
|
||||
static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args;
|
||||
|
||||
typedef typename std::conditional<IS_PACKED,
|
||||
internal::value<Context>, basic_format_arg<Context>>::type value_type;
|
||||
typedef typename std::conditional<IS_PACKED, internal::value<Context>,
|
||||
basic_format_arg<Context>>::type value_type;
|
||||
|
||||
// If the arguments are not packed, add one more element to mark the end.
|
||||
static const size_t DATA_SIZE =
|
||||
@ -1158,9 +1182,8 @@ class format_arg_store {
|
||||
friend class basic_format_args<Context>;
|
||||
|
||||
static FMT_CONSTEXPR11 unsigned long long get_types() {
|
||||
return IS_PACKED ?
|
||||
internal::get_types<Context, Args...>() :
|
||||
internal::is_unpacked_bit | NUM_ARGS;
|
||||
return IS_PACKED ? internal::get_types<Context, Args...>()
|
||||
: internal::is_unpacked_bit | NUM_ARGS;
|
||||
}
|
||||
|
||||
public:
|
||||
@ -1174,8 +1197,8 @@ class format_arg_store {
|
||||
(FMT_MSC_VER && FMT_MSC_VER <= 1800)
|
||||
// Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013.
|
||||
format_arg_store(const Args&... args) {
|
||||
value_type init[DATA_SIZE] =
|
||||
{internal::make_arg<IS_PACKED, Context>(args)...};
|
||||
value_type init[DATA_SIZE] = {
|
||||
internal::make_arg<IS_PACKED, Context>(args)...};
|
||||
std::memcpy(data_, init, sizeof(init));
|
||||
}
|
||||
#else
|
||||
@ -1198,12 +1221,13 @@ const unsigned long long format_arg_store<Context, Args...>::TYPES =
|
||||
\endrst
|
||||
*/
|
||||
template <typename Context = format_context, typename... Args>
|
||||
inline format_arg_store<Context, Args...>
|
||||
make_format_args(const Args &... args) { return {args...}; }
|
||||
inline format_arg_store<Context, Args...> make_format_args(
|
||||
const Args&... args) {
|
||||
return {args...};
|
||||
}
|
||||
|
||||
/** Formatting arguments. */
|
||||
template <typename Context>
|
||||
class basic_format_args {
|
||||
template <typename Context> class basic_format_args {
|
||||
public:
|
||||
typedef unsigned size_type;
|
||||
typedef basic_format_arg<Context> format_arg;
|
||||
@ -1226,8 +1250,8 @@ class basic_format_args {
|
||||
|
||||
typename internal::type type(unsigned index) const {
|
||||
unsigned shift = index * 4;
|
||||
return static_cast<typename internal::type>(
|
||||
(types_ & (0xfull << shift)) >> shift);
|
||||
return static_cast<typename internal::type>((types_ & (0xfull << shift)) >>
|
||||
shift);
|
||||
}
|
||||
|
||||
friend class internal::arg_map<Context>;
|
||||
@ -1239,15 +1263,12 @@ class basic_format_args {
|
||||
format_arg arg;
|
||||
if (!is_packed()) {
|
||||
auto num_args = max_size();
|
||||
if (index < num_args)
|
||||
arg = args_[index];
|
||||
if (index < num_args) arg = args_[index];
|
||||
return arg;
|
||||
}
|
||||
if (index > internal::max_packed_args)
|
||||
return arg;
|
||||
if (index > internal::max_packed_args) return arg;
|
||||
arg.type_ = type(index);
|
||||
if (arg.type_ == internal::none_type)
|
||||
return arg;
|
||||
if (arg.type_ == internal::none_type) return arg;
|
||||
internal::value<Context>& val = arg.value_;
|
||||
val = values_[index];
|
||||
return arg;
|
||||
@ -1313,37 +1334,34 @@ struct wformat_args : basic_format_args<wformat_context> {
|
||||
#if FMT_USE_ALIAS_TEMPLATES
|
||||
/** String's character type. */
|
||||
template <typename S>
|
||||
using char_t = FMT_ENABLE_IF_T(
|
||||
internal::is_string<S>::value, typename internal::char_t<S>::type);
|
||||
using char_t = FMT_ENABLE_IF_T(internal::is_string<S>::value,
|
||||
typename internal::char_t<S>::type);
|
||||
# define FMT_CHAR(S) fmt::char_t<S>
|
||||
#else
|
||||
template <typename S>
|
||||
struct char_t : std::enable_if<
|
||||
internal::is_string<S>::value, typename internal::char_t<S>::type> {};
|
||||
struct char_t : std::enable_if<internal::is_string<S>::value,
|
||||
typename internal::char_t<S>::type> {};
|
||||
# define FMT_CHAR(S) typename char_t<S>::type
|
||||
#endif
|
||||
|
||||
namespace internal {
|
||||
template <typename Char>
|
||||
struct named_arg_base {
|
||||
template <typename Char> struct named_arg_base {
|
||||
basic_string_view<Char> name;
|
||||
|
||||
// Serialized value<context>.
|
||||
mutable char data[
|
||||
sizeof(basic_format_arg<typename buffer_context<Char>::type>)];
|
||||
mutable char
|
||||
data[sizeof(basic_format_arg<typename buffer_context<Char>::type>)];
|
||||
|
||||
named_arg_base(basic_string_view<Char> nm) : name(nm) {}
|
||||
|
||||
template <typename Context>
|
||||
basic_format_arg<Context> deserialize() const {
|
||||
template <typename Context> basic_format_arg<Context> deserialize() const {
|
||||
basic_format_arg<Context> arg;
|
||||
std::memcpy(&arg, data, sizeof(basic_format_arg<Context>));
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct named_arg : named_arg_base<Char> {
|
||||
template <typename T, typename Char> struct named_arg : named_arg_base<Char> {
|
||||
const T& value;
|
||||
|
||||
named_arg(basic_string_view<Char> name, const T& val)
|
||||
@ -1354,16 +1372,16 @@ template <typename... Args, typename S>
|
||||
inline typename std::enable_if<!is_compile_string<S>::value>::type
|
||||
check_format_string(const S&) {}
|
||||
template <typename... Args, typename S>
|
||||
typename std::enable_if<is_compile_string<S>::value>::type
|
||||
check_format_string(S);
|
||||
typename std::enable_if<is_compile_string<S>::value>::type check_format_string(
|
||||
S);
|
||||
|
||||
template <typename S, typename... Args>
|
||||
struct checked_args : format_arg_store<
|
||||
typename buffer_context<FMT_CHAR(S)>::type, Args...> {
|
||||
struct checked_args
|
||||
: format_arg_store<typename buffer_context<FMT_CHAR(S)>::type, Args...> {
|
||||
typedef typename buffer_context<FMT_CHAR(S)>::type context;
|
||||
|
||||
checked_args(const S &format_str, const Args &... args):
|
||||
format_arg_store<context, Args...>(args...) {
|
||||
checked_args(const S& format_str, const Args&... args)
|
||||
: format_arg_store<context, Args...>(args...) {
|
||||
internal::check_format_string<Args...>(format_str);
|
||||
}
|
||||
|
||||
@ -1379,7 +1397,7 @@ template <typename Char>
|
||||
typename buffer_context<Char>::type::iterator vformat_to(
|
||||
internal::basic_buffer<Char>& buf, basic_string_view<Char> format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args);
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
\rst
|
||||
@ -1404,8 +1422,7 @@ inline internal::named_arg<T, wchar_t> arg(wstring_view name, const T &arg) {
|
||||
template <typename S, typename T, typename Char>
|
||||
void arg(S, internal::named_arg<T, Char>) = delete;
|
||||
|
||||
template <typename Container>
|
||||
struct is_contiguous: std::false_type {};
|
||||
template <typename Container> struct is_contiguous : std::false_type {};
|
||||
|
||||
template <typename Char>
|
||||
struct is_contiguous<std::basic_string<Char>> : std::true_type {};
|
||||
@ -1415,11 +1432,9 @@ struct is_contiguous<internal::basic_buffer<Char> >: std::true_type {};
|
||||
|
||||
/** Formats a string and writes the output to ``out``. */
|
||||
template <typename Container, typename S>
|
||||
typename std::enable_if<
|
||||
is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type
|
||||
vformat_to(
|
||||
std::back_insert_iterator<Container> out,
|
||||
const S &format_str,
|
||||
typename std::enable_if<is_contiguous<Container>::value,
|
||||
std::back_insert_iterator<Container>>::type
|
||||
vformat_to(std::back_insert_iterator<Container> out, const S& format_str,
|
||||
basic_format_args<typename buffer_context<FMT_CHAR(S)>::type> args) {
|
||||
internal::container_buffer<Container> buf(internal::get_container(out));
|
||||
internal::vformat_to(buf, to_string_view(format_str), args);
|
||||
@ -1427,8 +1442,8 @@ typename std::enable_if<
|
||||
}
|
||||
|
||||
template <typename Container, typename S, typename... Args>
|
||||
inline typename std::enable_if<
|
||||
is_contiguous<Container>::value && internal::is_string<S>::value,
|
||||
inline typename std::enable_if<is_contiguous<Container>::value &&
|
||||
internal::is_string<S>::value,
|
||||
std::back_insert_iterator<Container>>::type
|
||||
format_to(std::back_insert_iterator<Container> out, const S& format_str,
|
||||
const Args&... args) {
|
||||
@ -1454,8 +1469,8 @@ inline std::basic_string<Char> vformat(
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args>
|
||||
inline std::basic_string<FMT_CHAR(S)> format(
|
||||
const S &format_str, const Args &... args) {
|
||||
inline std::basic_string<FMT_CHAR(S)> format(const S& format_str,
|
||||
const Args&... args) {
|
||||
return internal::vformat(
|
||||
to_string_view(format_str),
|
||||
*internal::checked_args<S, Args...>(format_str, args...));
|
||||
|
@ -96,8 +96,8 @@ typedef void (*FormatFunc)(internal::buffer &, int, string_view);
|
||||
// ERANGE - buffer is not large enough to store the error message
|
||||
// other - failure
|
||||
// Buffer should be at least of size 1.
|
||||
int safe_strerror(
|
||||
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
|
||||
int safe_strerror(int error_code, char*& buffer,
|
||||
std::size_t buffer_size) FMT_NOEXCEPT {
|
||||
FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
|
||||
|
||||
class dispatcher {
|
||||
@ -132,8 +132,8 @@ int safe_strerror(
|
||||
// Fallback to strerror_s when strerror_r is not available.
|
||||
int fallback(int result) {
|
||||
// If the buffer is full then the message is probably truncated.
|
||||
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
|
||||
ERANGE : result;
|
||||
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? ERANGE
|
||||
: result;
|
||||
}
|
||||
|
||||
#if !FMT_MSC_VER
|
||||
@ -149,9 +149,7 @@ int safe_strerror(
|
||||
dispatcher(int err_code, char*& buf, std::size_t buf_size)
|
||||
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
|
||||
|
||||
int run() {
|
||||
return handle(strerror_r(error_code_, buffer_, buffer_size_));
|
||||
}
|
||||
int run() { return handle(strerror_r(error_code_, buffer_, buffer_size_)); }
|
||||
};
|
||||
return dispatcher(error_code, buffer, buffer_size).run();
|
||||
}
|
||||
@ -198,8 +196,7 @@ FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
|
||||
const char8_t* data = s.data();
|
||||
size_t num_code_points = 0;
|
||||
for (size_t i = 0, size = s.size(); i != size; ++i) {
|
||||
if ((data[i] & 0xc0) != 0x80)
|
||||
++num_code_points;
|
||||
if ((data[i] & 0xc0) != 0x80) ++num_code_points;
|
||||
}
|
||||
return num_code_points;
|
||||
}
|
||||
@ -212,18 +209,16 @@ locale_ref::locale_ref(const Locale &loc) : locale_(&loc) {
|
||||
static_assert(std::is_same<Locale, std::locale>::value, "");
|
||||
}
|
||||
|
||||
template <typename Locale>
|
||||
Locale locale_ref::get() const {
|
||||
template <typename Locale> Locale locale_ref::get() const {
|
||||
static_assert(std::is_same<Locale, std::locale>::value, "");
|
||||
return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_FUNC Char thousands_sep_impl(locale_ref loc) {
|
||||
return std::use_facet<std::numpunct<Char> >(
|
||||
loc.get<std::locale>()).thousands_sep();
|
||||
}
|
||||
template <typename Char> FMT_FUNC Char thousands_sep_impl(locale_ref loc) {
|
||||
return std::use_facet<std::numpunct<Char> >(loc.get<std::locale>())
|
||||
.thousands_sep();
|
||||
}
|
||||
} // namespace internal
|
||||
#else
|
||||
template <typename Char>
|
||||
FMT_FUNC Char internal::thousands_sep_impl(locale_ref) {
|
||||
@ -231,8 +226,8 @@ FMT_FUNC Char internal::thousands_sep_impl(locale_ref) {
|
||||
}
|
||||
#endif
|
||||
|
||||
FMT_FUNC void system_error::init(
|
||||
int err_code, string_view format_str, format_args args) {
|
||||
FMT_FUNC void system_error::init(int err_code, string_view format_str,
|
||||
format_args args) {
|
||||
error_code_ = err_code;
|
||||
memory_buffer buffer;
|
||||
format_system_error(buffer, err_code, vformat(format_str, args));
|
||||
@ -242,20 +237,19 @@ FMT_FUNC void system_error::init(
|
||||
|
||||
namespace internal {
|
||||
template <typename T>
|
||||
int char_traits<char>::format_float(
|
||||
char *buf, std::size_t size, const char *format, int precision, T value) {
|
||||
return precision < 0 ?
|
||||
FMT_SNPRINTF(buf, size, format, value) :
|
||||
FMT_SNPRINTF(buf, size, format, precision, value);
|
||||
int char_traits<char>::format_float(char* buf, std::size_t size,
|
||||
const char* format, int precision,
|
||||
T value) {
|
||||
return precision < 0 ? FMT_SNPRINTF(buf, size, format, value)
|
||||
: FMT_SNPRINTF(buf, size, format, precision, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int char_traits<wchar_t>::format_float(
|
||||
wchar_t *buf, std::size_t size, const wchar_t *format, int precision,
|
||||
int char_traits<wchar_t>::format_float(wchar_t* buf, std::size_t size,
|
||||
const wchar_t* format, int precision,
|
||||
T value) {
|
||||
return precision < 0 ?
|
||||
FMT_SWPRINTF(buf, size, format, value) :
|
||||
FMT_SWPRINTF(buf, size, format, precision, value);
|
||||
return precision < 0 ? FMT_SWPRINTF(buf, size, format, value)
|
||||
: FMT_SWPRINTF(buf, size, format, precision, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -267,33 +261,21 @@ const char basic_data<T>::DIGITS[] =
|
||||
"8081828384858687888990919293949596979899";
|
||||
|
||||
#define FMT_POWERS_OF_10(factor) \
|
||||
factor * 10, \
|
||||
factor * 100, \
|
||||
factor * 1000, \
|
||||
factor * 10000, \
|
||||
factor * 100000, \
|
||||
factor * 1000000, \
|
||||
factor * 10000000, \
|
||||
factor * 100000000, \
|
||||
factor * 10, factor * 100, factor * 1000, factor * 10000, factor * 100000, \
|
||||
factor * 1000000, factor * 10000000, factor * 100000000, \
|
||||
factor * 1000000000
|
||||
|
||||
template <typename T>
|
||||
const uint32_t basic_data<T>::POWERS_OF_10_32[] = {
|
||||
1, FMT_POWERS_OF_10(1)
|
||||
};
|
||||
const uint32_t basic_data<T>::POWERS_OF_10_32[] = {1, FMT_POWERS_OF_10(1)};
|
||||
|
||||
template <typename T>
|
||||
const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {
|
||||
0, FMT_POWERS_OF_10(1)
|
||||
};
|
||||
const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {0,
|
||||
FMT_POWERS_OF_10(1)};
|
||||
|
||||
template <typename T>
|
||||
const uint64_t basic_data<T>::ZERO_OR_POWERS_OF_10_64[] = {
|
||||
0,
|
||||
FMT_POWERS_OF_10(1),
|
||||
FMT_POWERS_OF_10(1000000000ull),
|
||||
10000000000000000000ull
|
||||
};
|
||||
0, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(1000000000ull),
|
||||
10000000000000000000ull};
|
||||
|
||||
// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
|
||||
// These are generated by support/compute-powers.py.
|
||||
@ -341,11 +323,12 @@ const int16_t basic_data<T>::POW10_EXPONENTS[] = {
|
||||
-50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216,
|
||||
242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508,
|
||||
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> const char basic_data<T>::BACKGROUND_COLOR[] = "\x1b[48;2;";
|
||||
template <typename T>
|
||||
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 wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
|
||||
|
||||
@ -376,8 +359,7 @@ class fp {
|
||||
|
||||
// Constructs fp from an IEEE754 double. It is a template to prevent compile
|
||||
// errors on platforms where double is not IEEE754.
|
||||
template <typename Double>
|
||||
explicit fp(Double d) {
|
||||
template <typename Double> explicit fp(Double d) {
|
||||
// Assume double is in the format [sign][exponent][significand].
|
||||
typedef std::numeric_limits<Double> limits;
|
||||
const int double_size = static_cast<int>(sizeof(Double) * char_size);
|
||||
@ -397,8 +379,7 @@ class fp {
|
||||
}
|
||||
|
||||
// Normalizes the value converted from double and multiplied by (1 << SHIFT).
|
||||
template <int SHIFT = 0>
|
||||
void normalize() {
|
||||
template <int SHIFT = 0> void normalize() {
|
||||
// Handle subnormals.
|
||||
auto shifted_implicit_bit = implicit_bit << SHIFT;
|
||||
while ((f & shifted_implicit_bit) == 0) {
|
||||
@ -416,8 +397,8 @@ class fp {
|
||||
// (lower) or successor (upper). The upper boundary is normalized and lower
|
||||
// has the same exponent but may be not normalized.
|
||||
void compute_boundaries(fp& lower, fp& upper) const {
|
||||
lower = f == implicit_bit ?
|
||||
fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1);
|
||||
lower =
|
||||
f == implicit_bit ? fp((f << 2) - 1, e - 2) : 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.
|
||||
lower.f <<= lower.e - upper.e;
|
||||
@ -432,7 +413,8 @@ inline fp operator-(fp x, fp y) {
|
||||
}
|
||||
|
||||
// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest
|
||||
// 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);
|
||||
|
||||
// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
|
||||
@ -452,8 +434,8 @@ FMT_FUNC fp operator*(fp x, fp y) {
|
||||
|
||||
FMT_FUNC fp get_cached_power(int min_exponent, int& pow10_exponent) {
|
||||
const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
|
||||
int index = static_cast<int>(std::ceil(
|
||||
(min_exponent + fp::significand_size - 1) * one_over_log2_10));
|
||||
int index = static_cast<int>(
|
||||
std::ceil((min_exponent + fp::significand_size - 1) * one_over_log2_10));
|
||||
// Decimal exponent of the first (smallest) cached power of 10.
|
||||
const int first_dec_exp = -348;
|
||||
// Difference between 2 consecutive decimal exponents in cached powers of 10.
|
||||
@ -463,10 +445,11 @@ FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
|
||||
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
|
||||
}
|
||||
|
||||
FMT_FUNC bool grisu2_round(
|
||||
char *buf, int &size, int max_digits, uint64_t delta,
|
||||
uint64_t remainder, uint64_t exp, uint64_t diff, int &exp10) {
|
||||
while (remainder < diff && delta - remainder >= exp &&
|
||||
FMT_FUNC bool grisu2_round(char* buf, int& size, int max_digits, uint64_t delta,
|
||||
uint64_t remainder, uint64_t exp, uint64_t diff,
|
||||
int& exp10) {
|
||||
while (
|
||||
remainder < diff && delta - remainder >= exp &&
|
||||
(remainder + exp < diff || diff - remainder > remainder + exp - diff)) {
|
||||
--buf[size - 1];
|
||||
remainder += exp;
|
||||
@ -474,44 +457,72 @@ FMT_FUNC bool grisu2_round(
|
||||
if (size > max_digits) {
|
||||
--size;
|
||||
++exp10;
|
||||
if (buf[size] >= '5')
|
||||
return false;
|
||||
if (buf[size] >= '5') return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generates output using Grisu2 digit-gen algorithm.
|
||||
FMT_FUNC bool grisu2_gen_digits(
|
||||
char *buf, int &size, uint32_t hi, uint64_t lo, int &exp,
|
||||
uint64_t delta, const fp &one, const fp &diff, int max_digits) {
|
||||
FMT_FUNC bool grisu2_gen_digits(char* buf, int& size, uint32_t hi, uint64_t lo,
|
||||
int& exp, uint64_t delta, const fp& one,
|
||||
const fp& diff, int max_digits) {
|
||||
// Generate digits for the most significant part (hi).
|
||||
while (exp > 0) {
|
||||
uint32_t digit = 0;
|
||||
// This optimization by miloyip reduces the number of integer divisions by
|
||||
// one per iteration.
|
||||
switch (exp) {
|
||||
case 10: digit = hi / 1000000000; hi %= 1000000000; break;
|
||||
case 9: digit = hi / 100000000; hi %= 100000000; break;
|
||||
case 8: 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;
|
||||
case 10:
|
||||
digit = hi / 1000000000;
|
||||
hi %= 1000000000;
|
||||
break;
|
||||
case 9:
|
||||
digit = hi / 100000000;
|
||||
hi %= 100000000;
|
||||
break;
|
||||
case 8:
|
||||
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:
|
||||
FMT_ASSERT(false, "invalid number of digits");
|
||||
}
|
||||
if (digit != 0 || size != 0)
|
||||
buf[size++] = static_cast<char>('0' + digit);
|
||||
if (digit != 0 || size != 0) buf[size++] = static_cast<char>('0' + digit);
|
||||
--exp;
|
||||
uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
|
||||
if (remainder <= delta || size > max_digits) {
|
||||
return grisu2_round(
|
||||
buf, size, max_digits, delta, remainder,
|
||||
static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e,
|
||||
diff.f, exp);
|
||||
static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e, diff.f,
|
||||
exp);
|
||||
}
|
||||
}
|
||||
// Generate digits for the least significant part (lo).
|
||||
@ -519,8 +530,7 @@ FMT_FUNC bool grisu2_gen_digits(
|
||||
lo *= 10;
|
||||
delta *= 10;
|
||||
char digit = static_cast<char>(lo >> -one.e);
|
||||
if (digit != 0 || size != 0)
|
||||
buf[size++] = static_cast<char>('0' + digit);
|
||||
if (digit != 0 || size != 0) buf[size++] = static_cast<char>('0' + digit);
|
||||
lo &= one.f - 1;
|
||||
--exp;
|
||||
if (lo < delta || size > max_digits) {
|
||||
@ -557,8 +567,7 @@ struct prettify_handler {
|
||||
buf.resize(to_unsigned(size));
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void insert(ptrdiff_t pos, ptrdiff_t n, F f) {
|
||||
template <typename F> void insert(ptrdiff_t pos, ptrdiff_t n, F f) {
|
||||
std::memmove(data + pos + n, data + pos, to_unsigned(size - pos));
|
||||
f(data + pos);
|
||||
size += n;
|
||||
@ -583,8 +592,7 @@ struct prettify_handler {
|
||||
};
|
||||
|
||||
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
|
||||
template <typename Handler>
|
||||
FMT_FUNC void write_exponent(int exp, Handler &&h) {
|
||||
template <typename Handler> FMT_FUNC void write_exponent(int exp, Handler&& h) {
|
||||
FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
|
||||
if (exp < 0) {
|
||||
h.append('-');
|
||||
@ -616,14 +624,13 @@ struct fill {
|
||||
|
||||
// The number is given as v = f * pow(10, exp), where f has size digits.
|
||||
template <typename Handler>
|
||||
FMT_FUNC void grisu2_prettify(const gen_digits_params ¶ms,
|
||||
int size, int exp, Handler &&handler) {
|
||||
FMT_FUNC void grisu2_prettify(const gen_digits_params& params, int size,
|
||||
int exp, Handler&& handler) {
|
||||
if (!params.fixed) {
|
||||
// Insert a decimal point after the first digit and add an exponent.
|
||||
handler.insert(1, '.');
|
||||
exp += size - 1;
|
||||
if (size < params.num_digits)
|
||||
handler.append(params.num_digits - size, '0');
|
||||
if (size < params.num_digits) handler.append(params.num_digits - size, '0');
|
||||
handler.append(params.upper ? 'E' : 'e');
|
||||
write_exponent(exp, handler);
|
||||
return;
|
||||
@ -659,8 +666,7 @@ FMT_FUNC void grisu2_prettify(const gen_digits_params ¶ms,
|
||||
struct char_counter {
|
||||
ptrdiff_t size;
|
||||
|
||||
template <typename F>
|
||||
void insert(ptrdiff_t, ptrdiff_t n, F) { size += n; }
|
||||
template <typename F> void insert(ptrdiff_t, ptrdiff_t n, F) { size += n; }
|
||||
void insert(ptrdiff_t, char) { ++size; }
|
||||
void append(ptrdiff_t n, char) { size += n; }
|
||||
void append(char) { ++size; }
|
||||
@ -678,7 +684,8 @@ FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,
|
||||
case 'G':
|
||||
params.upper = true;
|
||||
FMT_FALLTHROUGH
|
||||
case '\0': case 'g':
|
||||
case '\0':
|
||||
case 'g':
|
||||
params.trailing_zeros = (specs.flags & HASH_FLAG) != 0;
|
||||
if (-4 <= exp && exp < num_digits + 1) {
|
||||
params.fixed = true;
|
||||
@ -693,8 +700,7 @@ FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,
|
||||
params.fixed = true;
|
||||
params.trailing_zeros = true;
|
||||
int adjusted_min_digits = num_digits + exp;
|
||||
if (adjusted_min_digits > 0)
|
||||
num_digits = adjusted_min_digits;
|
||||
if (adjusted_min_digits > 0) num_digits = adjusted_min_digits;
|
||||
break;
|
||||
}
|
||||
case 'E':
|
||||
@ -771,14 +777,12 @@ void sprintf_format(Double value, internal::buffer &buf,
|
||||
char format[MAX_FORMAT_SIZE];
|
||||
char* format_ptr = format;
|
||||
*format_ptr++ = '%';
|
||||
if (spec.has(HASH_FLAG))
|
||||
*format_ptr++ = '#';
|
||||
if (spec.has(HASH_FLAG)) *format_ptr++ = '#';
|
||||
if (spec.precision >= 0) {
|
||||
*format_ptr++ = '.';
|
||||
*format_ptr++ = '*';
|
||||
}
|
||||
if (std::is_same<Double, long double>::value)
|
||||
*format_ptr++ = 'L';
|
||||
if (std::is_same<Double, long double>::value) *format_ptr++ = 'L';
|
||||
*format_ptr++ = spec.type;
|
||||
*format_ptr = '\0';
|
||||
|
||||
@ -819,15 +823,13 @@ FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
|
||||
return;
|
||||
}
|
||||
|
||||
int length = MultiByteToWideChar(
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
|
||||
if (length == 0)
|
||||
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
|
||||
int length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(),
|
||||
s_size, FMT_NULL, 0);
|
||||
if (length == 0) FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
|
||||
buffer_.resize(length + 1);
|
||||
length = MultiByteToWideChar(
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
|
||||
if (length == 0)
|
||||
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
|
||||
length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size,
|
||||
&buffer_[0], length);
|
||||
if (length == 0) FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
|
||||
buffer_[length] = 0;
|
||||
}
|
||||
|
||||
@ -839,8 +841,7 @@ FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
|
||||
}
|
||||
|
||||
FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
|
||||
if (s.size() > INT_MAX)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER;
|
||||
int s_size = static_cast<int>(s.size());
|
||||
if (s_size == 0) {
|
||||
// WideCharToMultiByte does not support zero length, handle separately.
|
||||
@ -849,21 +850,19 @@ FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int length = WideCharToMultiByte(
|
||||
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
|
||||
if (length == 0)
|
||||
return GetLastError();
|
||||
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0,
|
||||
FMT_NULL, FMT_NULL);
|
||||
if (length == 0) return GetLastError();
|
||||
buffer_.resize(length + 1);
|
||||
length = WideCharToMultiByte(
|
||||
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
|
||||
if (length == 0)
|
||||
return GetLastError();
|
||||
length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0],
|
||||
length, FMT_NULL, FMT_NULL);
|
||||
if (length == 0) return GetLastError();
|
||||
buffer_[length] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
FMT_FUNC void windows_error::init(
|
||||
int err_code, string_view format_str, format_args args) {
|
||||
FMT_FUNC void windows_error::init(int err_code, string_view format_str,
|
||||
format_args args) {
|
||||
error_code_ = err_code;
|
||||
memory_buffer buffer;
|
||||
internal::format_windows_error(buffer, err_code, vformat(format_str, args));
|
||||
@ -871,17 +870,18 @@ FMT_FUNC void windows_error::init(
|
||||
base = std::runtime_error(to_string(buffer));
|
||||
}
|
||||
|
||||
FMT_FUNC void internal::format_windows_error(
|
||||
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
|
||||
FMT_FUNC void internal::format_windows_error(internal::buffer& out,
|
||||
int error_code,
|
||||
string_view message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
wmemory_buffer buf;
|
||||
buf.resize(inline_buffer_size);
|
||||
for (;;) {
|
||||
wchar_t* system_message = &buf[0];
|
||||
int result = FormatMessageW(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
system_message, static_cast<uint32_t>(buf.size()), FMT_NULL);
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, FMT_NULL,
|
||||
error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message,
|
||||
static_cast<uint32_t>(buf.size()), FMT_NULL);
|
||||
if (result != 0) {
|
||||
utf16_to_utf8 utf8_message;
|
||||
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
|
||||
@ -897,14 +897,15 @@ FMT_FUNC void internal::format_windows_error(
|
||||
break; // Can't get error message, report error code instead.
|
||||
buf.resize(buf.size() * 2);
|
||||
}
|
||||
} FMT_CATCH(...) {}
|
||||
}
|
||||
FMT_CATCH(...) {}
|
||||
format_error_code(out, error_code, message);
|
||||
}
|
||||
|
||||
#endif // FMT_USE_WINDOWS_H
|
||||
|
||||
FMT_FUNC void format_system_error(
|
||||
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
|
||||
FMT_FUNC void format_system_error(internal::buffer& out, int error_code,
|
||||
string_view message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
memory_buffer buf;
|
||||
buf.resize(inline_buffer_size);
|
||||
@ -922,7 +923,8 @@ FMT_FUNC void format_system_error(
|
||||
break; // Can't get error message, report error code instead.
|
||||
buf.resize(buf.size() * 2);
|
||||
}
|
||||
} FMT_CATCH(...) {}
|
||||
}
|
||||
FMT_CATCH(...) {}
|
||||
format_error_code(out, error_code, message);
|
||||
}
|
||||
|
||||
@ -930,14 +932,14 @@ FMT_FUNC void internal::error_handler::on_error(const char *message) {
|
||||
FMT_THROW(format_error(message));
|
||||
}
|
||||
|
||||
FMT_FUNC void report_system_error(
|
||||
int error_code, fmt::string_view message) FMT_NOEXCEPT {
|
||||
FMT_FUNC void report_system_error(int error_code,
|
||||
fmt::string_view message) FMT_NOEXCEPT {
|
||||
report_error(format_system_error, error_code, message);
|
||||
}
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
FMT_FUNC void report_windows_error(
|
||||
int error_code, fmt::string_view message) FMT_NOEXCEPT {
|
||||
FMT_FUNC void report_windows_error(int error_code,
|
||||
fmt::string_view message) FMT_NOEXCEPT {
|
||||
report_error(internal::format_windows_error, error_code, message);
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,8 +8,8 @@
|
||||
#ifndef FMT_LOCALE_H_
|
||||
#define FMT_LOCALE_H_
|
||||
|
||||
#include "format.h"
|
||||
#include <locale>
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
@ -20,8 +20,8 @@ typename buffer_context<Char>::type::iterator vformat_to(
|
||||
basic_string_view<Char> format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
typedef back_insert_range<basic_buffer<Char>> range;
|
||||
return vformat_to<arg_formatter<range>>(
|
||||
buf, to_string_view(format_str), args, internal::locale_ref(loc));
|
||||
return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str), args,
|
||||
internal::locale_ref(loc));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
@ -32,7 +32,7 @@ std::basic_string<Char> vformat(
|
||||
internal::vformat_to(loc, buffer, format_str, args);
|
||||
return fmt::to_string(buffer);
|
||||
}
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
template <typename S, typename Char = FMT_CHAR(S)>
|
||||
inline std::basic_string<Char> vformat(
|
||||
@ -42,8 +42,9 @@ inline std::basic_string<Char> vformat(
|
||||
}
|
||||
|
||||
template <typename S, typename... Args>
|
||||
inline std::basic_string<FMT_CHAR(S)> format(
|
||||
const std::locale &loc, const S &format_str, const Args &... args) {
|
||||
inline std::basic_string<FMT_CHAR(S)> format(const std::locale& loc,
|
||||
const S& format_str,
|
||||
const Args&... args) {
|
||||
return internal::vformat(
|
||||
loc, to_string_view(format_str),
|
||||
*internal::checked_args<S, Args...>(format_str, args...));
|
||||
@ -60,9 +61,10 @@ inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args>
|
||||
inline typename std::enable_if<
|
||||
internal::is_string<S>::value &&
|
||||
internal::is_output_iterator<OutputIt>::value, OutputIt>::type
|
||||
inline
|
||||
typename std::enable_if<internal::is_string<S>::value &&
|
||||
internal::is_output_iterator<OutputIt>::value,
|
||||
OutputIt>::type
|
||||
format_to(OutputIt out, const std::locale& loc, const S& format_str,
|
||||
const Args&... args) {
|
||||
internal::check_format_string<Args...>(format_str);
|
||||
|
@ -8,14 +8,13 @@
|
||||
#ifndef FMT_OSTREAM_H_
|
||||
#define FMT_OSTREAM_H_
|
||||
|
||||
#include "format.h"
|
||||
#include <ostream>
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace internal {
|
||||
|
||||
template <class Char>
|
||||
class formatbuf : public std::basic_streambuf<Char> {
|
||||
template <class Char> class formatbuf : public std::basic_streambuf<Char> {
|
||||
private:
|
||||
typedef typename std::basic_streambuf<Char>::int_type int_type;
|
||||
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
|
||||
@ -45,25 +44,24 @@ class formatbuf : public std::basic_streambuf<Char> {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct test_stream : std::basic_ostream<Char> {
|
||||
template <typename Char> struct test_stream : std::basic_ostream<Char> {
|
||||
private:
|
||||
struct null;
|
||||
// Hide all operator<< from std::basic_ostream<Char>.
|
||||
void operator<<(null);
|
||||
};
|
||||
|
||||
// Checks if T has a user-defined operator<< (e.g. not a member of std::ostream).
|
||||
template <typename T, typename Char>
|
||||
class is_streamable {
|
||||
// Checks if T has a user-defined operator<< (e.g. not a member of
|
||||
// std::ostream).
|
||||
template <typename T, typename Char> class is_streamable {
|
||||
private:
|
||||
template <typename U>
|
||||
static decltype(
|
||||
internal::declval<test_stream<Char>&>()
|
||||
<< internal::declval<U>(), std::true_type()) test(int);
|
||||
static decltype(internal::declval<test_stream<Char>&>()
|
||||
<< internal::declval<U>(),
|
||||
std::true_type())
|
||||
test(int);
|
||||
|
||||
template <typename>
|
||||
static std::false_type test(...);
|
||||
template <typename> static std::false_type test(...);
|
||||
|
||||
typedef decltype(test<T>(0)) result;
|
||||
|
||||
@ -99,10 +97,8 @@ void format_value(basic_buffer<Char> &buffer, const T &value) {
|
||||
|
||||
// Disable conversion to int if T has an overloaded operator<< which is a free
|
||||
// function (not a member of std::ostream).
|
||||
template <typename T, typename Char>
|
||||
struct convert_to_int<T, Char, void> {
|
||||
static const bool value =
|
||||
convert_to_int<T, Char, int>::value &&
|
||||
template <typename T, typename Char> struct convert_to_int<T, Char, void> {
|
||||
static const bool value = convert_to_int<T, Char, int>::value &&
|
||||
!internal::is_streamable<T, Char>::value;
|
||||
};
|
||||
|
||||
@ -111,10 +107,9 @@ template <typename T, typename Char>
|
||||
struct formatter<T, Char,
|
||||
typename std::enable_if<
|
||||
internal::is_streamable<T, Char>::value &&
|
||||
!internal::format_type<
|
||||
typename buffer_context<Char>::type, T>::value>::type>
|
||||
!internal::format_type<typename buffer_context<Char>::type,
|
||||
T>::value>::type>
|
||||
: formatter<basic_string_view<Char>, Char> {
|
||||
|
||||
template <typename Context>
|
||||
auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
@ -125,8 +120,8 @@ struct formatter<T, Char,
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
inline void vprint(std::basic_ostream<Char> &os,
|
||||
basic_string_view<Char> format_str,
|
||||
inline void vprint(
|
||||
std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
internal::vformat_to(buffer, format_str, args);
|
||||
@ -142,8 +137,8 @@ inline void vprint(std::basic_ostream<Char> &os,
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args>
|
||||
inline typename std::enable_if<internal::is_string<S>::value>::type
|
||||
print(std::basic_ostream<FMT_CHAR(S)> &os, const S &format_str,
|
||||
inline typename std::enable_if<internal::is_string<S>::value>::type print(
|
||||
std::basic_ostream<FMT_CHAR(S)>& os, const S& format_str,
|
||||
const Args&... args) {
|
||||
internal::checked_args<S, Args...> ca(format_str, args...);
|
||||
vprint(os, to_string_view(format_str), *ca);
|
||||
|
@ -89,8 +89,7 @@ FMT_BEGIN_NAMESPACE
|
||||
format(std::string("{}"), 42);
|
||||
\endrst
|
||||
*/
|
||||
template <typename Char>
|
||||
class basic_cstring_view {
|
||||
template <typename Char> class basic_cstring_view {
|
||||
private:
|
||||
const Char* data_;
|
||||
|
||||
@ -143,7 +142,6 @@ class buffered_file {
|
||||
buffered_file(const buffered_file&) = delete;
|
||||
void operator=(const buffered_file&) = delete;
|
||||
|
||||
|
||||
public:
|
||||
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
|
||||
other.file_ = FMT_NULL;
|
||||
@ -211,9 +209,7 @@ class file {
|
||||
void operator=(const file&) = delete;
|
||||
|
||||
public:
|
||||
file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) {
|
||||
other.fd_ = -1;
|
||||
}
|
||||
file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
|
||||
|
||||
file& operator=(file&& other) {
|
||||
close();
|
||||
@ -284,9 +280,7 @@ class Locale {
|
||||
return _create_locale(category_mask, locale);
|
||||
}
|
||||
|
||||
static void freelocale(locale_t locale) {
|
||||
_free_locale(locale);
|
||||
}
|
||||
static void freelocale(locale_t locale) { _free_locale(locale); }
|
||||
|
||||
static double strtod_l(const char* nptr, char** endptr, _locale_t locale) {
|
||||
return _strtod_l(nptr, endptr, locale);
|
||||
@ -302,8 +296,7 @@ class Locale {
|
||||
typedef locale_t Type;
|
||||
|
||||
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
|
||||
if (!locale_)
|
||||
FMT_THROW(system_error(errno, "cannot create locale"));
|
||||
if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
|
||||
}
|
||||
~Locale() { freelocale(locale_); }
|
||||
|
||||
|
@ -73,7 +73,8 @@ template <typename Char> struct format_part {
|
||||
: which(which_value::argument_id), end_of_argument_id(0u), val(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) {}
|
||||
|
||||
FMT_CONSTEXPR format_part(specification spec)
|
||||
@ -99,7 +100,8 @@ template <typename Char> struct format_part {
|
||||
internal::string_view_metadata named_arg_id;
|
||||
internal::string_view_metadata text;
|
||||
specification spec;
|
||||
} val;
|
||||
}
|
||||
val;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
@ -151,8 +153,7 @@ public:
|
||||
|
||||
typedef basic_parse_context<Char> parse_context;
|
||||
internal::dynamic_format_specs<Char> parsed_specs;
|
||||
dynamic_specs_handler<parse_context> handler(
|
||||
parsed_specs, parse_context_);
|
||||
dynamic_specs_handler<parse_context> handler(parsed_specs, parse_context_);
|
||||
begin = parse_format_specs(begin, end, handler);
|
||||
|
||||
if (*begin != '}') {
|
||||
@ -241,9 +242,8 @@ class prepared_format {
|
||||
}
|
||||
|
||||
template <std::size_t SIZE = inline_buffer_size>
|
||||
inline typename buffer_context<char_type>::type::iterator
|
||||
format_to(basic_memory_buffer<char_type, SIZE> &buf,
|
||||
const Args &... args) const {
|
||||
inline typename buffer_context<char_type>::type::iterator format_to(
|
||||
basic_memory_buffer<char_type, SIZE>& buf, const Args&... args) const {
|
||||
typedef back_insert_range<internal::basic_buffer<char_type>> range;
|
||||
return this->vformat_to(range(buf), *checked_args(format_, args...));
|
||||
}
|
||||
@ -322,8 +322,8 @@ class prepared_format {
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void check_prepared_specs(
|
||||
const basic_format_specs<Char> &specs, internal::type arg_type) const {
|
||||
void check_prepared_specs(const basic_format_specs<Char>& specs,
|
||||
internal::type arg_type) const {
|
||||
internal::error_handler h;
|
||||
numeric_specs_checker<internal::error_handler> checker(h, arg_type);
|
||||
if (specs.align_ == ALIGN_NUMERIC) {
|
||||
|
@ -18,20 +18,16 @@ namespace internal {
|
||||
|
||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||
// signed and unsigned integers.
|
||||
template <bool IsSigned>
|
||||
struct int_checker {
|
||||
template <typename T>
|
||||
static bool fits_in_int(T value) {
|
||||
template <bool IsSigned> struct int_checker {
|
||||
template <typename T> static bool fits_in_int(T value) {
|
||||
unsigned max = std::numeric_limits<int>::max();
|
||||
return value <= max;
|
||||
}
|
||||
static bool fits_in_int(bool) { return true; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct int_checker<true> {
|
||||
template <typename T>
|
||||
static bool fits_in_int(T value) {
|
||||
template <> struct int_checker<true> {
|
||||
template <typename T> static bool fits_in_int(T value) {
|
||||
return value >= std::numeric_limits<int>::min() &&
|
||||
value <= std::numeric_limits<int>::max();
|
||||
}
|
||||
@ -41,15 +37,16 @@ struct int_checker<true> {
|
||||
class printf_precision_handler : public function<int> {
|
||||
public:
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value, int>::type
|
||||
operator()(T value) {
|
||||
typename std::enable_if<std::is_integral<T>::value, int>::type operator()(
|
||||
T value) {
|
||||
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||
FMT_THROW(format_error("number is too big"));
|
||||
return static_cast<int>(value);
|
||||
}
|
||||
|
||||
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"));
|
||||
return 0;
|
||||
}
|
||||
@ -59,21 +56,21 @@ class printf_precision_handler: public function<int> {
|
||||
class is_zero_int : public function<bool> {
|
||||
public:
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value, bool>::type
|
||||
operator()(T value) { return value == 0; }
|
||||
typename std::enable_if<std::is_integral<T>::value, bool>::type operator()(
|
||||
T value) {
|
||||
return value == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::is_integral<T>::value, bool>::type
|
||||
operator()(T) { return false; }
|
||||
typename std::enable_if<!std::is_integral<T>::value, bool>::type operator()(
|
||||
T) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct make_unsigned_or_bool : std::make_unsigned<T> {};
|
||||
template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {};
|
||||
|
||||
template <>
|
||||
struct make_unsigned_or_bool<bool> {
|
||||
typedef bool type;
|
||||
};
|
||||
template <> struct make_unsigned_or_bool<bool> { typedef bool type; };
|
||||
|
||||
template <typename T, typename Context>
|
||||
class arg_converter : public function<void> {
|
||||
@ -88,16 +85,15 @@ class arg_converter: public function<void> {
|
||||
: arg_(arg), type_(type) {}
|
||||
|
||||
void operator()(bool value) {
|
||||
if (type_ != 's')
|
||||
operator()<bool>(value);
|
||||
if (type_ != 's') operator()<bool>(value);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
typename std::enable_if<std::is_integral<U>::value>::type
|
||||
operator()(U value) {
|
||||
typename std::enable_if<std::is_integral<U>::value>::type operator()(
|
||||
U value) {
|
||||
bool is_signed = type_ == 'd' || type_ == 'i';
|
||||
typedef typename std::conditional<
|
||||
std::is_same<T, void>::value, U, T>::type TargetType;
|
||||
typedef typename std::conditional<std::is_same<T, void>::value, U, T>::type
|
||||
TargetType;
|
||||
if (const_check(sizeof(TargetType) <= sizeof(int))) {
|
||||
// Extra casts are used to silence warnings.
|
||||
if (is_signed) {
|
||||
@ -137,8 +133,7 @@ void convert_arg(basic_format_arg<Context> &arg, Char type) {
|
||||
}
|
||||
|
||||
// Converts an integer argument to char for printf.
|
||||
template <typename Context>
|
||||
class char_converter: public function<void> {
|
||||
template <typename Context> class char_converter : public function<void> {
|
||||
private:
|
||||
basic_format_arg<Context>& arg_;
|
||||
|
||||
@ -146,8 +141,8 @@ class char_converter: public function<void> {
|
||||
explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value>::type
|
||||
operator()(T value) {
|
||||
typename std::enable_if<std::is_integral<T>::value>::type operator()(
|
||||
T value) {
|
||||
typedef typename Context::char_type Char;
|
||||
arg_ = internal::make_arg<Context>(static_cast<Char>(value));
|
||||
}
|
||||
@ -180,8 +175,7 @@ class printf_width_handler: public function<unsigned> {
|
||||
width = 0 - width;
|
||||
}
|
||||
unsigned int_max = std::numeric_limits<int>::max();
|
||||
if (width > int_max)
|
||||
FMT_THROW(format_error("number is too big"));
|
||||
if (width > int_max) FMT_THROW(format_error("number is too big"));
|
||||
return static_cast<unsigned>(width);
|
||||
}
|
||||
|
||||
@ -202,13 +196,11 @@ void printf(basic_buffer<Char> &buf, basic_string_view<Char> format,
|
||||
|
||||
using internal::printf; // For printing into memory_buffer.
|
||||
|
||||
template <typename Range>
|
||||
class printf_arg_formatter;
|
||||
template <typename Range> class printf_arg_formatter;
|
||||
|
||||
template <
|
||||
typename OutputIt, typename Char,
|
||||
typename ArgFormatter =
|
||||
printf_arg_formatter<back_insert_range<internal::basic_buffer<Char>>>>
|
||||
template <typename OutputIt, typename Char,
|
||||
typename ArgFormatter = printf_arg_formatter<
|
||||
back_insert_range<internal::basic_buffer<Char>>>>
|
||||
class basic_printf_context;
|
||||
|
||||
/**
|
||||
@ -217,8 +209,8 @@ class basic_printf_context;
|
||||
\endrst
|
||||
*/
|
||||
template <typename Range>
|
||||
class printf_arg_formatter:
|
||||
public internal::function<
|
||||
class printf_arg_formatter
|
||||
: public internal::function<
|
||||
typename internal::arg_formatter_base<Range>::iterator>,
|
||||
public internal::arg_formatter_base<Range> {
|
||||
private:
|
||||
@ -251,8 +243,8 @@ class printf_arg_formatter:
|
||||
*/
|
||||
printf_arg_formatter(internal::basic_buffer<char_type>& buffer,
|
||||
format_specs& spec, context_type& ctx)
|
||||
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec,
|
||||
ctx.locale()),
|
||||
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer),
|
||||
&spec, ctx.locale()),
|
||||
context_(ctx) {}
|
||||
|
||||
template <typename T>
|
||||
@ -262,8 +254,7 @@ class printf_arg_formatter:
|
||||
// use std::is_same instead.
|
||||
if (std::is_same<T, bool>::value) {
|
||||
format_specs& fmt_spec = *this->spec();
|
||||
if (fmt_spec.type != 's')
|
||||
return base::operator()(value ? 1 : 0);
|
||||
if (fmt_spec.type != 's') return base::operator()(value ? 1 : 0);
|
||||
fmt_spec.type = 0;
|
||||
this->write(value != 0);
|
||||
} else if (std::is_same<T, char_type>::value) {
|
||||
@ -311,14 +302,11 @@ class printf_arg_formatter:
|
||||
return base::operator()(value);
|
||||
}
|
||||
|
||||
iterator operator()(monostate value) {
|
||||
return base::operator()(value);
|
||||
}
|
||||
iterator operator()(monostate value) { return base::operator()(value); }
|
||||
|
||||
/** Formats a pointer. */
|
||||
iterator operator()(const void* value) {
|
||||
if (value)
|
||||
return base::operator()(value);
|
||||
if (value) return base::operator()(value);
|
||||
this->spec()->type = 0;
|
||||
write_null_pointer(char_type());
|
||||
return this->out();
|
||||
@ -331,10 +319,11 @@ class printf_arg_formatter:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct printf_formatter {
|
||||
template <typename T> struct printf_formatter {
|
||||
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>
|
||||
auto format(const T& value, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||
@ -354,8 +343,9 @@ class basic_printf_context :
|
||||
/** The character type for the output. */
|
||||
typedef Char char_type;
|
||||
|
||||
template <typename T>
|
||||
struct formatter_type { typedef printf_formatter<T> type; };
|
||||
template <typename T> struct formatter_type {
|
||||
typedef printf_formatter<T> type;
|
||||
};
|
||||
|
||||
private:
|
||||
typedef internal::context_base<OutputIt, basic_printf_context, Char> base;
|
||||
@ -383,17 +373,18 @@ class basic_printf_context :
|
||||
basic_format_args<basic_printf_context> args)
|
||||
: base(out, format_str, args) {}
|
||||
|
||||
using base::parse_context;
|
||||
using base::out;
|
||||
using base::advance_to;
|
||||
using base::out;
|
||||
using base::parse_context;
|
||||
|
||||
/** Formats stored arguments and writes the output to the range. */
|
||||
void format();
|
||||
};
|
||||
|
||||
template <typename OutputIt, typename Char, typename AF>
|
||||
void basic_printf_context<OutputIt, Char, AF>::parse_flags(
|
||||
format_specs &spec, const Char *&it, const Char *end) {
|
||||
void basic_printf_context<OutputIt, Char, AF>::parse_flags(format_specs& spec,
|
||||
const Char*& it,
|
||||
const Char* end) {
|
||||
for (; it != end; ++it) {
|
||||
switch (*it) {
|
||||
case '-':
|
||||
@ -439,8 +430,7 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
|
||||
++it;
|
||||
arg_index = value;
|
||||
} else {
|
||||
if (c == '0')
|
||||
spec.fill_ = '0';
|
||||
if (c == '0') spec.fill_ = '0';
|
||||
if (value != 0) {
|
||||
// Nonzero value means that we parsed width and don't need to
|
||||
// parse it or flags again, so return now.
|
||||
@ -505,7 +495,8 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
|
||||
|
||||
format_arg arg = get_arg(arg_index);
|
||||
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 (arg.is_arithmetic())
|
||||
spec.align_ = ALIGN_NUMERIC;
|
||||
@ -555,19 +546,19 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
|
||||
}
|
||||
|
||||
// Parse type.
|
||||
if (it == end)
|
||||
FMT_THROW(format_error("invalid format string"));
|
||||
if (it == end) FMT_THROW(format_error("invalid format string"));
|
||||
spec.type = static_cast<char>(*it++);
|
||||
if (arg.is_integral()) {
|
||||
// Normalize type.
|
||||
switch (spec.type) {
|
||||
case 'i': case 'u':
|
||||
case 'i':
|
||||
case 'u':
|
||||
spec.type = 'd';
|
||||
break;
|
||||
case 'c':
|
||||
// TODO: handle wchar_t better?
|
||||
visit_format_arg(
|
||||
internal::char_converter<basic_printf_context>(arg), arg);
|
||||
visit_format_arg(internal::char_converter<basic_printf_context>(arg),
|
||||
arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -580,10 +571,10 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
|
||||
buffer.append(start, it);
|
||||
}
|
||||
|
||||
template <typename Buffer>
|
||||
struct basic_printf_context_t {
|
||||
typedef basic_printf_context<
|
||||
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
|
||||
template <typename Buffer> struct basic_printf_context_t {
|
||||
typedef basic_printf_context<std::back_insert_iterator<Buffer>,
|
||||
typename Buffer::value_type>
|
||||
type;
|
||||
};
|
||||
|
||||
typedef basic_printf_context_t<internal::buffer>::type printf_context;
|
||||
@ -599,8 +590,10 @@ typedef basic_format_args<wprintf_context> wprintf_args;
|
||||
\endrst
|
||||
*/
|
||||
template <typename... Args>
|
||||
inline format_arg_store<printf_context, Args...>
|
||||
make_printf_args(const Args &... args) { return {args...}; }
|
||||
inline format_arg_store<printf_context, Args...> make_printf_args(
|
||||
const Args&... args) {
|
||||
return {args...};
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
@ -609,14 +602,17 @@ inline format_arg_store<printf_context, Args...>
|
||||
\endrst
|
||||
*/
|
||||
template <typename... Args>
|
||||
inline format_arg_store<wprintf_context, Args...>
|
||||
make_wprintf_args(const Args &... args) { return {args...}; }
|
||||
inline format_arg_store<wprintf_context, Args...> make_wprintf_args(
|
||||
const Args&... args) {
|
||||
return {args...};
|
||||
}
|
||||
|
||||
template <typename S, typename Char = FMT_CHAR(S)>
|
||||
inline std::basic_string<Char>
|
||||
vsprintf(const S &format,
|
||||
basic_format_args<typename basic_printf_context_t<
|
||||
internal::basic_buffer<Char>>::type> args) {
|
||||
inline std::basic_string<Char> vsprintf(
|
||||
const S& format,
|
||||
basic_format_args<
|
||||
typename basic_printf_context_t<internal::basic_buffer<Char>>::type>
|
||||
args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
printf(buffer, to_string_view(format), args);
|
||||
return to_string(buffer);
|
||||
@ -632,26 +628,28 @@ vsprintf(const S &format,
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args>
|
||||
inline FMT_ENABLE_IF_T(
|
||||
internal::is_string<S>::value, std::basic_string<FMT_CHAR(S)>)
|
||||
inline FMT_ENABLE_IF_T(internal::is_string<S>::value,
|
||||
std::basic_string<FMT_CHAR(S)>)
|
||||
sprintf(const S& format, const Args&... args) {
|
||||
internal::check_format_string<Args...>(format);
|
||||
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
|
||||
typedef typename basic_printf_context_t<buffer>::type context;
|
||||
format_arg_store<context, Args...> as{args...};
|
||||
return vsprintf(to_string_view(format),
|
||||
basic_format_args<context>(as));
|
||||
return vsprintf(to_string_view(format), basic_format_args<context>(as));
|
||||
}
|
||||
|
||||
template <typename S, typename Char = FMT_CHAR(S)>
|
||||
inline int vfprintf(std::FILE *f, const S &format,
|
||||
basic_format_args<typename basic_printf_context_t<
|
||||
internal::basic_buffer<Char>>::type> args) {
|
||||
inline int vfprintf(
|
||||
std::FILE* f, const S& format,
|
||||
basic_format_args<
|
||||
typename basic_printf_context_t<internal::basic_buffer<Char>>::type>
|
||||
args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
printf(buffer, to_string_view(format), args);
|
||||
std::size_t size = buffer.size();
|
||||
return std::fwrite(
|
||||
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);
|
||||
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
|
||||
? -1
|
||||
: static_cast<int>(size);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -670,14 +668,15 @@ inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
|
||||
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
|
||||
typedef typename basic_printf_context_t<buffer>::type context;
|
||||
format_arg_store<context, Args...> as{args...};
|
||||
return vfprintf(f, to_string_view(format),
|
||||
basic_format_args<context>(as));
|
||||
return vfprintf(f, to_string_view(format), basic_format_args<context>(as));
|
||||
}
|
||||
|
||||
template <typename S, typename Char = FMT_CHAR(S)>
|
||||
inline int vprintf(const S &format,
|
||||
basic_format_args<typename basic_printf_context_t<
|
||||
internal::basic_buffer<Char>>::type> args) {
|
||||
inline int vprintf(
|
||||
const S& format,
|
||||
basic_format_args<
|
||||
typename basic_printf_context_t<internal::basic_buffer<Char>>::type>
|
||||
args) {
|
||||
return vfprintf(stdout, to_string_view(format), args);
|
||||
}
|
||||
|
||||
@ -697,15 +696,15 @@ inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
|
||||
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
|
||||
typedef typename basic_printf_context_t<buffer>::type context;
|
||||
format_arg_store<context, Args...> as{args...};
|
||||
return vprintf(to_string_view(format_str),
|
||||
basic_format_args<context>(as));
|
||||
return vprintf(to_string_view(format_str), basic_format_args<context>(as));
|
||||
}
|
||||
|
||||
template <typename S, typename Char = FMT_CHAR(S)>
|
||||
inline int vfprintf(std::basic_ostream<Char> &os,
|
||||
const S &format,
|
||||
basic_format_args<typename basic_printf_context_t<
|
||||
internal::basic_buffer<Char>>::type> args) {
|
||||
inline int vfprintf(
|
||||
std::basic_ostream<Char>& os, const S& format,
|
||||
basic_format_args<
|
||||
typename basic_printf_context_t<internal::basic_buffer<Char>>::type>
|
||||
args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
printf(buffer, to_string_view(format), args);
|
||||
internal::write(os, buffer);
|
||||
@ -723,8 +722,8 @@ inline int vfprintf(std::basic_ostream<Char> &os,
|
||||
*/
|
||||
template <typename S, typename... Args>
|
||||
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
|
||||
fprintf(std::basic_ostream<FMT_CHAR(S)> &os,
|
||||
const S &format_str, const Args & ... args) {
|
||||
fprintf(std::basic_ostream<FMT_CHAR(S)>& os, const S& format_str,
|
||||
const Args&... args) {
|
||||
internal::check_format_string<Args...>(format_str);
|
||||
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
|
||||
typedef typename basic_printf_context_t<buffer>::type context;
|
||||
|
@ -12,8 +12,8 @@
|
||||
#ifndef FMT_RANGES_H_
|
||||
#define FMT_RANGES_H_
|
||||
|
||||
#include "format.h"
|
||||
#include <type_traits>
|
||||
#include "format.h"
|
||||
|
||||
// output only up to N items from the range.
|
||||
#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
|
||||
@ -22,8 +22,7 @@
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
template <typename Char>
|
||||
struct formatting_base {
|
||||
template <typename Char> struct formatting_base {
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
@ -33,7 +32,8 @@ struct formatting_base {
|
||||
template <typename Char, typename Enable = void>
|
||||
struct formatting_range : formatting_base<Char> {
|
||||
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 delimiter;
|
||||
Char postfix;
|
||||
@ -68,19 +68,16 @@ void copy(const char *str, OutputIterator out) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename OutputIterator>
|
||||
void copy(char ch, OutputIterator out) {
|
||||
template <typename OutputIterator> void copy(char ch, OutputIterator out) {
|
||||
*out++ = ch;
|
||||
}
|
||||
|
||||
/// Return true value if T has std::string interface, like std::string_view.
|
||||
template <typename T>
|
||||
class is_like_std_string {
|
||||
template <typename T> class is_like_std_string {
|
||||
template <typename U>
|
||||
static auto check(U *p) ->
|
||||
decltype(p->find('a'), p->length(), p->data(), int());
|
||||
template <typename>
|
||||
static void check(...);
|
||||
static auto check(U* p)
|
||||
-> decltype(p->find('a'), p->length(), p->data(), int());
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
@ -90,15 +87,14 @@ class is_like_std_string {
|
||||
template <typename Char>
|
||||
struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {};
|
||||
|
||||
template <typename... Ts>
|
||||
struct conditional_helper {};
|
||||
template <typename... Ts> struct conditional_helper {};
|
||||
|
||||
template <typename T, typename _ = void>
|
||||
struct is_range_ : std::false_type {};
|
||||
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||
|
||||
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
|
||||
template <typename T>
|
||||
struct is_range_<T, typename std::conditional<
|
||||
struct is_range_<
|
||||
T, typename std::conditional<
|
||||
false,
|
||||
conditional_helper<decltype(internal::declval<T>().begin()),
|
||||
decltype(internal::declval<T>().end())>,
|
||||
@ -106,14 +102,13 @@ struct is_range_<T, typename std::conditional<
|
||||
#endif
|
||||
|
||||
/// tuple_size and tuple_element check.
|
||||
template <typename T>
|
||||
class is_tuple_like_ {
|
||||
template <typename T> class is_tuple_like_ {
|
||||
template <typename U>
|
||||
static auto check(U *p) ->
|
||||
decltype(std::tuple_size<U>::value,
|
||||
internal::declval<typename std::tuple_element<0, U>::type>(), int());
|
||||
template <typename>
|
||||
static void check(...);
|
||||
static auto check(U* p)
|
||||
-> decltype(std::tuple_size<U>::value,
|
||||
internal::declval<typename std::tuple_element<0, U>::type>(),
|
||||
int());
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
@ -124,18 +119,14 @@ class is_tuple_like_ {
|
||||
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
|
||||
template <typename T, T... N>
|
||||
using integer_sequence = std::integer_sequence<T, N...>;
|
||||
template <std::size_t... N>
|
||||
using index_sequence = std::index_sequence<N...>;
|
||||
template <std::size_t... N> using index_sequence = std::index_sequence<N...>;
|
||||
template <std::size_t N>
|
||||
using make_index_sequence = std::make_index_sequence<N>;
|
||||
#else
|
||||
template <typename T, T... N>
|
||||
struct integer_sequence {
|
||||
template <typename T, T... N> struct integer_sequence {
|
||||
typedef T value_type;
|
||||
|
||||
static FMT_CONSTEXPR std::size_t size() {
|
||||
return sizeof...(N);
|
||||
}
|
||||
static FMT_CONSTEXPR std::size_t size() { return sizeof...(N); }
|
||||
};
|
||||
|
||||
template <std::size_t... N>
|
||||
@ -159,26 +150,31 @@ void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT {
|
||||
}
|
||||
|
||||
template <class T>
|
||||
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value>
|
||||
get_indexes(T const &) { return {}; }
|
||||
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(
|
||||
T const&) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <class Tuple, class F>
|
||||
void for_each(Tuple &&tup, F &&f) {
|
||||
template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
|
||||
const auto indexes = get_indexes(tup);
|
||||
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
|
||||
FMT_CONSTEXPR const char* format_str_quoted(
|
||||
bool add_space, const Arg&,
|
||||
typename std::enable_if<
|
||||
!is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
|
||||
!is_like_std_string<typename std::decay<Arg>::type>::value>::type* =
|
||||
nullptr) {
|
||||
return add_space ? " {}" : "{}";
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
|
||||
FMT_CONSTEXPR const char* format_str_quoted(
|
||||
bool add_space, const Arg&,
|
||||
typename std::enable_if<
|
||||
is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
|
||||
is_like_std_string<typename std::decay<Arg>::type>::value>::type* =
|
||||
nullptr) {
|
||||
return add_space ? " \"{}\"" : "\"{}\"";
|
||||
}
|
||||
|
||||
@ -198,21 +194,19 @@ FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T>
|
||||
struct is_tuple_like {
|
||||
template <typename T> struct is_tuple_like {
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
|
||||
};
|
||||
|
||||
template <typename TupleT, typename Char>
|
||||
struct formatter<TupleT, Char,
|
||||
struct formatter<
|
||||
TupleT, Char,
|
||||
typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> {
|
||||
private:
|
||||
// C++11 generic lambda for format()
|
||||
template <typename FormatContext>
|
||||
struct format_each {
|
||||
template <typename T>
|
||||
void operator()(const T& v) {
|
||||
template <typename FormatContext> struct format_each {
|
||||
template <typename T> void operator()(const T& v) {
|
||||
if (i > 0) {
|
||||
if (formatting.add_prepostfix_space) {
|
||||
*out++ = ' ';
|
||||
@ -228,7 +222,8 @@ private:
|
||||
|
||||
formatting_tuple<Char>& formatting;
|
||||
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:
|
||||
@ -255,8 +250,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_range {
|
||||
template <typename T> struct is_range {
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
internal::is_range_<T>::value && !internal::is_like_std_string<T>::value;
|
||||
};
|
||||
@ -264,7 +258,6 @@ struct is_range {
|
||||
template <typename RangeT, typename Char>
|
||||
struct formatter<RangeT, Char,
|
||||
typename std::enable_if<fmt::is_range<RangeT>::value>::type> {
|
||||
|
||||
formatting_range<Char> formatting;
|
||||
|
||||
template <typename ParseContext>
|
||||
@ -273,8 +266,8 @@ struct formatter<RangeT, Char,
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
typename FormatContext::iterator format(
|
||||
const RangeT &values, FormatContext &ctx) {
|
||||
typename FormatContext::iterator format(const RangeT& values,
|
||||
FormatContext& ctx) {
|
||||
auto out = ctx.out();
|
||||
internal::copy(formatting.prefix, out);
|
||||
std::size_t i = 0;
|
||||
@ -305,4 +298,3 @@ struct formatter<RangeT, Char,
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_RANGES_H_
|
||||
|
||||
|
@ -8,9 +8,9 @@
|
||||
#ifndef FMT_TIME_H_
|
||||
#define FMT_TIME_H_
|
||||
|
||||
#include "format.h"
|
||||
#include <ctime>
|
||||
#include <locale>
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
@ -58,8 +58,7 @@ inline std::tm localtime(std::time_t time) {
|
||||
};
|
||||
dispatcher lt(time);
|
||||
// Too big time values may be unsupported.
|
||||
if (!lt.run())
|
||||
FMT_THROW(format_error("time_t value out of range"));
|
||||
if (!lt.run()) FMT_THROW(format_error("time_t value out of range"));
|
||||
return lt.tm_;
|
||||
}
|
||||
|
||||
@ -95,8 +94,7 @@ inline std::tm gmtime(std::time_t time) {
|
||||
};
|
||||
dispatcher gt(time);
|
||||
// Too big time values may be unsupported.
|
||||
if (!gt.run())
|
||||
FMT_THROW(format_error("time_t value out of range"));
|
||||
if (!gt.run()) FMT_THROW(format_error("time_t value out of range"));
|
||||
return gt.tm_;
|
||||
}
|
||||
|
||||
@ -110,18 +108,15 @@ inline std::size_t strftime(wchar_t *str, std::size_t count,
|
||||
const wchar_t* format, const std::tm* time) {
|
||||
return std::wcsftime(str, count, format, time);
|
||||
}
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
template <typename Char>
|
||||
struct formatter<std::tm, Char> {
|
||||
template <typename Char> struct formatter<std::tm, Char> {
|
||||
template <typename ParseContext>
|
||||
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
auto it = ctx.begin();
|
||||
if (it != ctx.end() && *it == ':')
|
||||
++it;
|
||||
if (it != ctx.end() && *it == ':') ++it;
|
||||
auto end = it;
|
||||
while (end != ctx.end() && *end != '}')
|
||||
++end;
|
||||
while (end != ctx.end() && *end != '}') ++end;
|
||||
tm_format.reserve(internal::to_unsigned(end - it + 1));
|
||||
tm_format.append(it, end);
|
||||
tm_format.push_back('\0');
|
||||
|
@ -16,16 +16,21 @@ template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
|
||||
|
||||
template FMT_API char internal::thousands_sep_impl(locale_ref);
|
||||
|
||||
template FMT_API 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(
|
||||
const basic_format_args<format_context>& args);
|
||||
|
||||
template FMT_API int internal::char_traits<char>::format_float(
|
||||
char *, std::size_t, const char *, int, double);
|
||||
template FMT_API int internal::char_traits<char>::format_float(char*,
|
||||
std::size_t,
|
||||
const char*, int,
|
||||
double);
|
||||
|
||||
template FMT_API int internal::char_traits<char>::format_float(
|
||||
char *, std::size_t, const char *, int, long double);
|
||||
template FMT_API int internal::char_traits<char>::format_float(char*,
|
||||
std::size_t,
|
||||
const char*, int,
|
||||
long double);
|
||||
|
||||
template FMT_API std::string internal::vformat<char>(
|
||||
string_view, basic_format_args<format_context>);
|
||||
@ -33,17 +38,17 @@ template FMT_API std::string internal::vformat<char>(
|
||||
template FMT_API format_context::iterator internal::vformat_to(
|
||||
internal::buffer&, string_view, basic_format_args<format_context>);
|
||||
|
||||
template FMT_API void internal::sprintf_format(
|
||||
double, internal::buffer &, core_format_specs);
|
||||
template FMT_API void internal::sprintf_format(
|
||||
long double, internal::buffer &, core_format_specs);
|
||||
template FMT_API void internal::sprintf_format(double, internal::buffer&,
|
||||
core_format_specs);
|
||||
template FMT_API void internal::sprintf_format(long double, internal::buffer&,
|
||||
core_format_specs);
|
||||
|
||||
// Explicit instantiations for wchar_t.
|
||||
|
||||
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
|
||||
|
||||
template FMT_API void internal::basic_buffer<wchar_t>::append(
|
||||
const wchar_t *, const wchar_t *);
|
||||
template FMT_API void internal::basic_buffer<wchar_t>::append(const wchar_t*,
|
||||
const wchar_t*);
|
||||
|
||||
template FMT_API void internal::arg_map<wformat_context>::init(
|
||||
const basic_format_args<wformat_context>&);
|
||||
|
49
src/posix.cc
49
src/posix.cc
@ -13,8 +13,8 @@
|
||||
#include "fmt/posix.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
@ -22,8 +22,8 @@
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
# include <windows.h>
|
||||
|
||||
# define O_CREAT _O_CREAT
|
||||
# define O_TRUNC _O_TRUNC
|
||||
@ -62,7 +62,7 @@ typedef ssize_t RWResult;
|
||||
|
||||
inline std::size_t convert_rwcount(std::size_t count) { return count; }
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
@ -72,19 +72,17 @@ buffered_file::~buffered_file() FMT_NOEXCEPT {
|
||||
}
|
||||
|
||||
buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
|
||||
FMT_RETRY_VAL(file_,
|
||||
FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), FMT_NULL);
|
||||
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
|
||||
FMT_NULL);
|
||||
if (!file_)
|
||||
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
|
||||
}
|
||||
|
||||
void buffered_file::close() {
|
||||
if (!file_)
|
||||
return;
|
||||
if (!file_) return;
|
||||
int result = FMT_SYSTEM(fclose(file_));
|
||||
file_ = FMT_NULL;
|
||||
if (result != 0)
|
||||
FMT_THROW(system_error(errno, "cannot close file"));
|
||||
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
|
||||
}
|
||||
|
||||
// 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 fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
|
||||
if (fd == -1)
|
||||
FMT_THROW(system_error(errno, "cannot get file descriptor"));
|
||||
if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor"));
|
||||
return fd;
|
||||
}
|
||||
|
||||
@ -117,14 +114,12 @@ file::~file() FMT_NOEXCEPT {
|
||||
}
|
||||
|
||||
void file::close() {
|
||||
if (fd_ == -1)
|
||||
return;
|
||||
if (fd_ == -1) return;
|
||||
// Don't retry close in case of EINTR!
|
||||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||
int result = FMT_POSIX_CALL(close(fd_));
|
||||
fd_ = -1;
|
||||
if (result != 0)
|
||||
FMT_THROW(system_error(errno, "cannot close file"));
|
||||
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
|
||||
}
|
||||
|
||||
long long file::size() const {
|
||||
@ -156,16 +151,14 @@ long long file::size() const {
|
||||
std::size_t file::read(void* buffer, std::size_t count) {
|
||||
RWResult result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
|
||||
if (result < 0)
|
||||
FMT_THROW(system_error(errno, "cannot read from file"));
|
||||
if (result < 0) FMT_THROW(system_error(errno, "cannot read from file"));
|
||||
return internal::to_unsigned(result);
|
||||
}
|
||||
|
||||
std::size_t file::write(const void* buffer, std::size_t count) {
|
||||
RWResult result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
|
||||
if (result < 0)
|
||||
FMT_THROW(system_error(errno, "cannot write to file"));
|
||||
if (result < 0) FMT_THROW(system_error(errno, "cannot write to file"));
|
||||
return internal::to_unsigned(result);
|
||||
}
|
||||
|
||||
@ -182,16 +175,15 @@ void file::dup2(int fd) {
|
||||
int result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||
if (result == -1) {
|
||||
FMT_THROW(system_error(errno,
|
||||
"cannot duplicate file descriptor {} to {}", fd_, fd));
|
||||
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {} to {}",
|
||||
fd_, fd));
|
||||
}
|
||||
}
|
||||
|
||||
void file::dup2(int fd, error_code& ec) FMT_NOEXCEPT {
|
||||
int result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||
if (result == -1)
|
||||
ec = error_code(errno);
|
||||
if (result == -1) ec = error_code(errno);
|
||||
}
|
||||
|
||||
void file::pipe(file& read_end, file& write_end) {
|
||||
@ -209,8 +201,7 @@ void file::pipe(file &read_end, file &write_end) {
|
||||
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
|
||||
int result = FMT_POSIX_CALL(pipe(fds));
|
||||
#endif
|
||||
if (result != 0)
|
||||
FMT_THROW(system_error(errno, "cannot create pipe"));
|
||||
if (result != 0) FMT_THROW(system_error(errno, "cannot create pipe"));
|
||||
// The following assignments don't throw because read_fd and write_fd
|
||||
// are closed.
|
||||
read_end = file(fds[0]);
|
||||
@ -221,8 +212,8 @@ buffered_file file::fdopen(const char *mode) {
|
||||
// Don't retry as fdopen doesn't return EINTR.
|
||||
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
|
||||
if (!f)
|
||||
FMT_THROW(system_error(errno,
|
||||
"cannot associate stream with file descriptor"));
|
||||
FMT_THROW(
|
||||
system_error(errno, "cannot associate stream with file descriptor"));
|
||||
buffered_file bf(f);
|
||||
fd_ = -1;
|
||||
return bf;
|
||||
@ -235,10 +226,8 @@ long getpagesize() {
|
||||
return si.dwPageSize;
|
||||
#else
|
||||
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
|
||||
if (size < 0)
|
||||
FMT_THROW(system_error(errno, "cannot get memory page size"));
|
||||
if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size"));
|
||||
return size;
|
||||
#endif
|
||||
}
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
|
@ -17,6 +17,6 @@
|
||||
#endif
|
||||
|
||||
TEST(AssertTest, Fail) {
|
||||
EXPECT_DEBUG_DEATH_IF_SUPPORTED(
|
||||
FMT_ASSERT(false, "don't panic!"), "don't panic!");
|
||||
EXPECT_DEBUG_DEATH_IF_SUPPORTED(FMT_ASSERT(false, "don't panic!"),
|
||||
"don't panic!");
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ std::string format_tm(const std::tm &time, const char *spec,
|
||||
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), \
|
||||
fmt::format(loc, "{:" spec "}", duration)); \
|
||||
@ -83,12 +84,12 @@ TEST(ChronoTest, FormatDefault) {
|
||||
fmt::format("{}", std::chrono::duration<int, std::exa>(42)));
|
||||
EXPECT_EQ("42m", fmt::format("{}", std::chrono::minutes(42)));
|
||||
EXPECT_EQ("42h", fmt::format("{}", std::chrono::hours(42)));
|
||||
EXPECT_EQ("42[15]s",
|
||||
fmt::format("{}",
|
||||
std::chrono::duration<int, std::ratio<15, 1>>(42)));
|
||||
EXPECT_EQ("42[15/4]s",
|
||||
fmt::format("{}",
|
||||
std::chrono::duration<int, std::ratio<15, 4>>(42)));
|
||||
EXPECT_EQ(
|
||||
"42[15]s",
|
||||
fmt::format("{}", std::chrono::duration<int, std::ratio<15, 1>>(42)));
|
||||
EXPECT_EQ(
|
||||
"42[15/4]s",
|
||||
fmt::format("{}", std::chrono::duration<int, std::ratio<15, 4>>(42)));
|
||||
}
|
||||
|
||||
TEST(ChronoTest, Align) {
|
||||
@ -105,7 +106,6 @@ TEST(ChronoTest, Align) {
|
||||
fmt::format("{:~^12%H:%M:%S}", std::chrono::seconds(12345)));
|
||||
EXPECT_EQ("03:25:45 ",
|
||||
fmt::format("{:{}%H:%M:%S}", std::chrono::seconds(12345), 12));
|
||||
|
||||
}
|
||||
|
||||
TEST(ChronoTest, FormatSpecs) {
|
||||
@ -168,7 +168,8 @@ TEST(ChronoTest, Locale) {
|
||||
try {
|
||||
loc = std::locale(loc_name);
|
||||
has_locale = true;
|
||||
} catch (const std::runtime_error &) {}
|
||||
} catch (const std::runtime_error&) {
|
||||
}
|
||||
if (!has_locale) {
|
||||
fmt::print("{} locale is missing.\n", loc_name);
|
||||
return;
|
||||
|
@ -11,9 +11,9 @@
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
|
||||
#include "test-assert.h"
|
||||
|
||||
@ -30,9 +30,9 @@
|
||||
#undef max
|
||||
|
||||
using fmt::basic_format_arg;
|
||||
using fmt::string_view;
|
||||
using fmt::internal::basic_buffer;
|
||||
using fmt::internal::value;
|
||||
using fmt::string_view;
|
||||
|
||||
using testing::_;
|
||||
using testing::StrictMock;
|
||||
@ -48,8 +48,7 @@ basic_format_arg<Context> make_arg(const T &value) {
|
||||
} // namespace
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <typename Char>
|
||||
struct formatter<test_struct, Char> {
|
||||
template <typename Char> struct formatter<test_struct, Char> {
|
||||
template <typename ParseContext>
|
||||
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
@ -84,13 +83,11 @@ TEST(BufferTest, Nonmoveable) {
|
||||
#endif
|
||||
|
||||
// A test buffer with a dummy grow method.
|
||||
template <typename T>
|
||||
struct test_buffer : basic_buffer<T> {
|
||||
template <typename T> struct test_buffer : basic_buffer<T> {
|
||||
void grow(std::size_t capacity) { this->set(FMT_NULL, capacity); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct mock_buffer : basic_buffer<T> {
|
||||
template <typename T> struct mock_buffer : basic_buffer<T> {
|
||||
MOCK_METHOD1(do_grow, void(std::size_t capacity));
|
||||
|
||||
void grow(std::size_t capacity) {
|
||||
@ -211,8 +208,7 @@ TEST(ArgTest, FormatArgs) {
|
||||
struct custom_context {
|
||||
typedef char char_type;
|
||||
|
||||
template <typename T>
|
||||
struct formatter_type {
|
||||
template <typename T> struct formatter_type {
|
||||
struct type {
|
||||
template <typename ParseContext>
|
||||
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
@ -249,17 +245,15 @@ template <typename Char>
|
||||
bool operator==(custom_value<Char> lhs, custom_value<Char> rhs) {
|
||||
return lhs.value == rhs.value;
|
||||
}
|
||||
}
|
||||
} // namespace internal
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
// Use a unique result type to make sure that there are no undesirable
|
||||
// conversions.
|
||||
struct test_result {};
|
||||
|
||||
template <typename T>
|
||||
struct mock_visitor {
|
||||
template <typename U>
|
||||
struct result { typedef test_result type; };
|
||||
template <typename T> struct mock_visitor {
|
||||
template <typename U> struct result { typedef test_result type; };
|
||||
|
||||
mock_visitor() {
|
||||
ON_CALL(*this, visit(_)).WillByDefault(testing::Return(test_result()));
|
||||
@ -270,19 +264,16 @@ struct mock_visitor {
|
||||
|
||||
test_result operator()(T value) { return visit(value); }
|
||||
|
||||
template <typename U>
|
||||
test_result operator()(U) {
|
||||
template <typename U> test_result operator()(U) {
|
||||
unexpected();
|
||||
return test_result();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct visit_type { typedef T Type; };
|
||||
template <typename T> struct visit_type { typedef T Type; };
|
||||
|
||||
#define VISIT_TYPE(Type_, visit_type_) \
|
||||
template <> \
|
||||
struct visit_type<Type_> { typedef visit_type_ Type; }
|
||||
template <> struct visit_type<Type_> { typedef visit_type_ Type; }
|
||||
|
||||
VISIT_TYPE(signed char, int);
|
||||
VISIT_TYPE(unsigned char, unsigned);
|
||||
@ -299,7 +290,8 @@ VISIT_TYPE(unsigned long, unsigned long long);
|
||||
|
||||
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)); \
|
||||
typedef std::back_insert_iterator<basic_buffer<Char>> iterator; \
|
||||
@ -307,20 +299,21 @@ VISIT_TYPE(float, double);
|
||||
make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
|
||||
}
|
||||
|
||||
#define CHECK_ARG(value, typename_) { \
|
||||
#define CHECK_ARG(value, typename_) \
|
||||
{ \
|
||||
typedef decltype(value) value_type; \
|
||||
typename_ visit_type<value_type>::Type expected = value; \
|
||||
CHECK_ARG_(char, expected, value) \
|
||||
CHECK_ARG_(wchar_t, expected, value) \
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class NumericArgTest : public testing::Test {};
|
||||
template <typename T> class NumericArgTest : public testing::Test {};
|
||||
|
||||
typedef ::testing::Types<
|
||||
bool, signed char, unsigned char, signed, unsigned short,
|
||||
int, unsigned, long, unsigned long, long long, unsigned long long,
|
||||
float, double, long double> Types;
|
||||
typedef ::testing::Types<bool, signed char, unsigned char, signed,
|
||||
unsigned short, int, unsigned, long, unsigned long,
|
||||
long long, unsigned long long, float, double,
|
||||
long double>
|
||||
Types;
|
||||
TYPED_TEST_CASE(NumericArgTest, Types);
|
||||
|
||||
template <typename T>
|
||||
@ -416,8 +409,7 @@ TEST(StringViewTest, Length) {
|
||||
}
|
||||
|
||||
// Check string_view's comparison operator.
|
||||
template <template <typename> class Op>
|
||||
void check_op() {
|
||||
template <template <typename> class Op> void check_op() {
|
||||
const char* inputs[] = {"foo", "fop", "fo"};
|
||||
std::size_t num_inputs = sizeof(inputs) / sizeof(*inputs);
|
||||
for (std::size_t i = 0; i < num_inputs; ++i) {
|
||||
@ -457,25 +449,25 @@ TEST(CoreTest, IsEnumConvertibleToInt) {
|
||||
}
|
||||
|
||||
namespace my_ns {
|
||||
template <typename Char>
|
||||
class my_string {
|
||||
template <typename Char> class my_string {
|
||||
public:
|
||||
my_string(const Char* s) : s_(s) {}
|
||||
const Char* data() const FMT_NOEXCEPT { return s_.data(); }
|
||||
std::size_t length() const FMT_NOEXCEPT { return s_.size(); }
|
||||
operator const Char*() const { return s_.c_str(); }
|
||||
|
||||
private:
|
||||
std::basic_string<Char> s_;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
inline fmt::basic_string_view<Char>
|
||||
to_string_view(const my_string<Char> &s) FMT_NOEXCEPT {
|
||||
inline fmt::basic_string_view<Char> to_string_view(const my_string<Char>& s)
|
||||
FMT_NOEXCEPT {
|
||||
return {s.data(), s.length()};
|
||||
}
|
||||
|
||||
struct non_string {};
|
||||
}
|
||||
} // namespace my_ns
|
||||
|
||||
namespace FakeQt {
|
||||
class QString {
|
||||
@ -490,15 +482,13 @@ class QString {
|
||||
std::shared_ptr<std::wstring> s_;
|
||||
};
|
||||
|
||||
inline fmt::basic_string_view<wchar_t> to_string_view(
|
||||
const QString &s) FMT_NOEXCEPT {
|
||||
return {s.utf16(),
|
||||
static_cast<std::size_t>(s.size())};
|
||||
}
|
||||
inline fmt::basic_string_view<wchar_t> to_string_view(const QString& s)
|
||||
FMT_NOEXCEPT {
|
||||
return {s.utf16(), static_cast<std::size_t>(s.size())};
|
||||
}
|
||||
} // namespace FakeQt
|
||||
|
||||
template <typename T>
|
||||
class IsStringTest : public testing::Test {};
|
||||
template <typename T> class IsStringTest : public testing::Test {};
|
||||
|
||||
typedef ::testing::Types<char, wchar_t, char16_t, char32_t> StringCharTypes;
|
||||
TYPED_TEST_CASE(IsStringTest, StringCharTypes);
|
||||
@ -506,7 +496,7 @@ TYPED_TEST_CASE(IsStringTest, StringCharTypes);
|
||||
namespace {
|
||||
template <typename Char>
|
||||
struct derived_from_string_view : fmt::basic_string_view<Char> {};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TYPED_TEST(IsStringTest, IsString) {
|
||||
EXPECT_TRUE((fmt::internal::is_string<TypeParam*>::value));
|
||||
@ -600,11 +590,12 @@ TEST(FormatterTest, FormatExplicitlyConvertibleToWStringView) {
|
||||
}
|
||||
|
||||
struct explicitly_convertible_to_string_like {
|
||||
template <
|
||||
typename String,
|
||||
typename = typename std::enable_if<
|
||||
std::is_constructible<String, const char*, std::size_t>::value>::type>
|
||||
FMT_EXPLICIT operator String() const { return String("foo", 3u); }
|
||||
template <typename String,
|
||||
typename = typename std::enable_if<std::is_constructible<
|
||||
String, const char*, std::size_t>::value>::type>
|
||||
FMT_EXPLICIT operator String() const {
|
||||
return String("foo", 3u);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(FormatterTest, FormatExplicitlyConvertibleToStringLike) {
|
||||
|
@ -13,22 +13,21 @@
|
||||
|
||||
// A custom argument formatter that doesn't print `-` for floating-point values
|
||||
// rounded to 0.
|
||||
class custom_arg_formatter :
|
||||
public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
|
||||
class custom_arg_formatter
|
||||
: public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
|
||||
public:
|
||||
typedef fmt::back_insert_range<fmt::internal::buffer> range;
|
||||
typedef fmt::arg_formatter<range> base;
|
||||
|
||||
custom_arg_formatter(
|
||||
fmt::format_context &ctx, fmt::format_specs *s = FMT_NULL)
|
||||
custom_arg_formatter(fmt::format_context& ctx,
|
||||
fmt::format_specs* s = FMT_NULL)
|
||||
: base(ctx, s) {}
|
||||
|
||||
using base::operator();
|
||||
|
||||
iterator operator()(double value) {
|
||||
// Comparing a float to 0.0 is safe.
|
||||
if (round(value * pow(10, spec()->precision)) == 0.0)
|
||||
value = 0;
|
||||
if (round(value * pow(10, spec()->precision)) == 0.0) value = 0;
|
||||
return base::operator()(value);
|
||||
}
|
||||
};
|
||||
|
@ -32,13 +32,11 @@
|
||||
|
||||
using fmt::internal::fp;
|
||||
|
||||
template <bool is_iec559>
|
||||
void test_construct_from_double() {
|
||||
template <bool is_iec559> void test_construct_from_double() {
|
||||
fmt::print("warning: double is not IEC559, skipping FP tests\n");
|
||||
}
|
||||
|
||||
template <>
|
||||
void test_construct_from_double<true>() {
|
||||
template <> void test_construct_from_double<true>() {
|
||||
auto v = fp(1.23);
|
||||
EXPECT_EQ(v.f, 0x13ae147ae147aeu);
|
||||
EXPECT_EQ(v.e, -52);
|
||||
@ -107,14 +105,10 @@ TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) {
|
||||
grisu2_format(4.2f, buf, fmt::core_format_specs());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct ValueExtractor: fmt::internal::function<T> {
|
||||
T operator()(T value) {
|
||||
return value;
|
||||
}
|
||||
template <typename T> struct ValueExtractor : fmt::internal::function<T> {
|
||||
T operator()(T value) { return value; }
|
||||
|
||||
template <typename U>
|
||||
FMT_NORETURN T operator()(U) {
|
||||
template <typename U> FMT_NORETURN T operator()(U) {
|
||||
throw std::runtime_error(fmt::format("invalid type {}", typeid(U).name()));
|
||||
}
|
||||
};
|
||||
@ -178,8 +172,8 @@ TEST(FormatTest, FormatErrorCode) {
|
||||
}
|
||||
{
|
||||
fmt::memory_buffer buffer;
|
||||
std::string prefix(
|
||||
fmt::inline_buffer_size - msg.size() - sep.size() + 1, 'x');
|
||||
std::string prefix(fmt::inline_buffer_size - msg.size() - sep.size() + 1,
|
||||
'x');
|
||||
fmt::format_error_code(buffer, 42, prefix);
|
||||
EXPECT_EQ(msg, to_string(buffer));
|
||||
}
|
||||
@ -188,8 +182,7 @@ TEST(FormatTest, FormatErrorCode) {
|
||||
// Test maximum buffer size.
|
||||
msg = fmt::format("error {}", codes[i]);
|
||||
fmt::memory_buffer buffer;
|
||||
std::string prefix(
|
||||
fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
|
||||
std::string prefix(fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
|
||||
fmt::format_error_code(buffer, codes[i], prefix);
|
||||
EXPECT_EQ(prefix + sep + msg, to_string(buffer));
|
||||
std::size_t size = fmt::inline_buffer_size;
|
||||
@ -250,17 +243,18 @@ TEST(ColorsTest, ColorsFormat) {
|
||||
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue"),
|
||||
"\x1b[38;2;000;000;255mblue\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fg(fmt::color::blue) | bg(fmt::color::red), "two color"),
|
||||
EXPECT_EQ(
|
||||
fmt::format(fg(fmt::color::blue) | bg(fmt::color::red), "two color"),
|
||||
"\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold"),
|
||||
"\x1b[1mbold\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold"), "\x1b[1mbold\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::italic, "italic"),
|
||||
"\x1b[3mitalic\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::underline, "underline"),
|
||||
"\x1b[4munderline\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::strikethrough, "strikethrough"),
|
||||
"\x1b[9mstrikethrough\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"),
|
||||
EXPECT_EQ(
|
||||
fmt::format(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"),
|
||||
"\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m");
|
||||
EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold error"),
|
||||
"\x1b[1mbold error\x1b[0m");
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -7,11 +7,11 @@
|
||||
|
||||
#include "gtest-extra.h"
|
||||
|
||||
#include <gtest/gtest-spi.h>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <gtest/gtest-spi.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
# include <crtdbg.h> // for _CrtSetReportMode
|
||||
@ -52,13 +52,9 @@ int SingleEvaluationTest::b_;
|
||||
|
||||
void do_nothing() {}
|
||||
|
||||
void throw_exception() {
|
||||
throw std::runtime_error("test");
|
||||
}
|
||||
void throw_exception() { throw std::runtime_error("test"); }
|
||||
|
||||
void throw_system_error() {
|
||||
throw fmt::system_error(EDOM, "test");
|
||||
}
|
||||
void throw_system_error() { throw fmt::system_error(EDOM, "test"); }
|
||||
|
||||
// Tests that when EXPECT_THROW_MSG fails, it evaluates its message argument
|
||||
// exactly once.
|
||||
@ -71,42 +67,49 @@ TEST_F(SingleEvaluationTest, FailedEXPECT_THROW_MSG) {
|
||||
// Tests that when EXPECT_SYSTEM_ERROR fails, it evaluates its message argument
|
||||
// exactly once.
|
||||
TEST_F(SingleEvaluationTest, FailedEXPECT_SYSTEM_ERROR) {
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, p_++), "01234");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, p_++),
|
||||
"01234");
|
||||
EXPECT_EQ(s_ + 1, p_);
|
||||
}
|
||||
|
||||
// Tests that when EXPECT_WRITE fails, it evaluates its message argument
|
||||
// exactly once.
|
||||
TEST_F(SingleEvaluationTest, FailedEXPECT_WRITE) {
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_WRITE(stdout, std::printf("test"), p_++), "01234");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), p_++),
|
||||
"01234");
|
||||
EXPECT_EQ(s_ + 1, p_);
|
||||
}
|
||||
|
||||
// Tests that assertion arguments are evaluated exactly once.
|
||||
TEST_F(SingleEvaluationTest, ExceptionTests) {
|
||||
// successful EXPECT_THROW_MSG
|
||||
EXPECT_THROW_MSG({ // NOLINT
|
||||
EXPECT_THROW_MSG(
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
throw_exception();
|
||||
}, std::exception, (b_++, "test"));
|
||||
},
|
||||
std::exception, (b_++, "test"));
|
||||
EXPECT_EQ(1, a_);
|
||||
EXPECT_EQ(1, b_);
|
||||
|
||||
// failed EXPECT_THROW_MSG, throws different type
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG({ // NOLINT
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
throw_exception();
|
||||
}, std::logic_error, (b_++, "test")), "throws a different type");
|
||||
},
|
||||
std::logic_error, (b_++, "test")),
|
||||
"throws a different type");
|
||||
EXPECT_EQ(2, a_);
|
||||
EXPECT_EQ(2, b_);
|
||||
|
||||
// failed EXPECT_THROW_MSG, throws an exception with different message
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG({ // NOLINT
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
throw_exception();
|
||||
}, std::exception, (b_++, "other")),
|
||||
},
|
||||
std::exception, (b_++, "other")),
|
||||
"throws an exception with a different message");
|
||||
EXPECT_EQ(3, a_);
|
||||
EXPECT_EQ(3, b_);
|
||||
@ -120,33 +123,40 @@ TEST_F(SingleEvaluationTest, ExceptionTests) {
|
||||
|
||||
TEST_F(SingleEvaluationTest, SystemErrorTests) {
|
||||
// successful EXPECT_SYSTEM_ERROR
|
||||
EXPECT_SYSTEM_ERROR({ // NOLINT
|
||||
EXPECT_SYSTEM_ERROR(
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
throw_system_error();
|
||||
}, EDOM, (b_++, "test"));
|
||||
},
|
||||
EDOM, (b_++, "test"));
|
||||
EXPECT_EQ(1, a_);
|
||||
EXPECT_EQ(1, b_);
|
||||
|
||||
// failed EXPECT_SYSTEM_ERROR, throws different type
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR({ // NOLINT
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
throw_exception();
|
||||
}, EDOM, (b_++, "test")), "throws a different type");
|
||||
},
|
||||
EDOM, (b_++, "test")),
|
||||
"throws a different type");
|
||||
EXPECT_EQ(2, a_);
|
||||
EXPECT_EQ(2, b_);
|
||||
|
||||
// failed EXPECT_SYSTEM_ERROR, throws an exception with different message
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR({ // NOLINT
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
throw_system_error();
|
||||
}, EDOM, (b_++, "other")),
|
||||
},
|
||||
EDOM, (b_++, "other")),
|
||||
"throws an exception with a different message");
|
||||
EXPECT_EQ(3, a_);
|
||||
EXPECT_EQ(3, b_);
|
||||
|
||||
// failed EXPECT_SYSTEM_ERROR, throws nothing
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_SYSTEM_ERROR(a_++, EDOM, (b_++, "test")), "throws nothing");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(a_++, EDOM, (b_++, "test")),
|
||||
"throws nothing");
|
||||
EXPECT_EQ(4, a_);
|
||||
EXPECT_EQ(4, b_);
|
||||
}
|
||||
@ -154,18 +164,23 @@ TEST_F(SingleEvaluationTest, SystemErrorTests) {
|
||||
// Tests that assertion arguments are evaluated exactly once.
|
||||
TEST_F(SingleEvaluationTest, WriteTests) {
|
||||
// successful EXPECT_WRITE
|
||||
EXPECT_WRITE(stdout, { // NOLINT
|
||||
EXPECT_WRITE(stdout,
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
std::printf("test");
|
||||
}, (b_++, "test"));
|
||||
},
|
||||
(b_++, "test"));
|
||||
EXPECT_EQ(1, a_);
|
||||
EXPECT_EQ(1, b_);
|
||||
|
||||
// failed EXPECT_WRITE
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, { // NOLINT
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout,
|
||||
{ // NOLINT
|
||||
a_++;
|
||||
std::printf("test");
|
||||
}, (b_++, "other")), "Actual: test");
|
||||
},
|
||||
(b_++, "other")),
|
||||
"Actual: test");
|
||||
EXPECT_EQ(2, a_);
|
||||
EXPECT_EQ(2, b_);
|
||||
}
|
||||
@ -178,8 +193,8 @@ TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) {
|
||||
EXPECT_THROW_MSG(throw runtime_error(""), runtime_error, "");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(n++, runtime_error, ""), "");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(throw 1, runtime_error, ""), "");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(
|
||||
throw runtime_error("a"), runtime_error, "b"), "");
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_THROW_MSG(throw runtime_error("a"), runtime_error, "b"), "");
|
||||
}
|
||||
|
||||
// Tests that the compiler will not complain about unreachable code in the
|
||||
@ -189,8 +204,9 @@ TEST(ExpectSystemErrorTest, DoesNotGenerateUnreachableCodeWarning) {
|
||||
EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "test"), EDOM, "test");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(n++, EDOM, ""), "");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw 1, EDOM, ""), "");
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
|
||||
throw fmt::system_error(EDOM, "aaa"), EDOM, "bbb"), "");
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "aaa"), EDOM, "bbb"),
|
||||
"");
|
||||
}
|
||||
|
||||
TEST(AssertionSyntaxTest, ExceptionAssertionBehavesLikeSingleStatement) {
|
||||
@ -267,8 +283,7 @@ TEST(ExpectTest, EXPECT_WRITE) {
|
||||
EXPECT_WRITE(stdout, do_nothing(), "");
|
||||
EXPECT_WRITE(stdout, std::printf("test"), "test");
|
||||
EXPECT_WRITE(stderr, std::fprintf(stderr, "test"), "test");
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_WRITE(stdout, std::printf("that"), "this"),
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("that"), "this"),
|
||||
"Expected: this\n"
|
||||
" Actual: that");
|
||||
}
|
||||
@ -278,7 +293,8 @@ TEST(StreamingAssertionsTest, EXPECT_THROW_MSG) {
|
||||
<< "unexpected failure";
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_THROW_MSG(throw_exception(), std::exception, "other")
|
||||
<< "expected failure", "expected failure");
|
||||
<< "expected failure",
|
||||
"expected failure");
|
||||
}
|
||||
|
||||
TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) {
|
||||
@ -286,15 +302,15 @@ TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) {
|
||||
<< "unexpected failure";
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other")
|
||||
<< "expected failure", "expected failure");
|
||||
<< "expected failure",
|
||||
"expected failure");
|
||||
}
|
||||
|
||||
TEST(StreamingAssertionsTest, EXPECT_WRITE) {
|
||||
EXPECT_WRITE(stdout, std::printf("test"), "test")
|
||||
<< "unexpected failure";
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
EXPECT_WRITE(stdout, std::printf("test"), "other")
|
||||
<< "expected failure", "expected failure");
|
||||
EXPECT_WRITE(stdout, std::printf("test"), "test") << "unexpected failure";
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), "other")
|
||||
<< "expected failure",
|
||||
"expected failure");
|
||||
}
|
||||
|
||||
TEST(UtilTest, FormatSystemError) {
|
||||
@ -340,8 +356,8 @@ TEST(OutputRedirectTest, FlushErrorInCtor) {
|
||||
EXPECT_EQ('x', fputc('x', f.get()));
|
||||
FMT_POSIX(close(write_fd));
|
||||
std::unique_ptr<OutputRedirect> redir{FMT_NULL};
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
|
||||
EBADF, "cannot flush stream");
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())), EBADF,
|
||||
"cannot flush stream");
|
||||
redir.reset(FMT_NULL);
|
||||
write_copy.dup2(write_fd); // "undo" close or dtor will fail
|
||||
}
|
||||
@ -352,8 +368,9 @@ TEST(OutputRedirectTest, DupErrorInCtor) {
|
||||
file copy = file::dup(fd);
|
||||
FMT_POSIX(close(fd));
|
||||
std::unique_ptr<OutputRedirect> redir{FMT_NULL};
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
|
||||
EBADF, fmt::format("cannot duplicate file descriptor {}", fd));
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(
|
||||
redir.reset(new OutputRedirect(f.get())), EBADF,
|
||||
fmt::format("cannot duplicate file descriptor {}", fd));
|
||||
copy.dup2(fd); // "undo" close or dtor will fail
|
||||
}
|
||||
|
||||
@ -382,8 +399,8 @@ TEST(OutputRedirectTest, FlushErrorInRestoreAndRead) {
|
||||
// Put a character in a file buffer.
|
||||
EXPECT_EQ('x', fputc('x', f.get()));
|
||||
FMT_POSIX(close(write_fd));
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(redir.restore_and_read(),
|
||||
EBADF, "cannot flush stream");
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(redir.restore_and_read(), EBADF,
|
||||
"cannot flush stream");
|
||||
write_copy.dup2(write_fd); // "undo" close or dtor will fail
|
||||
}
|
||||
|
||||
@ -396,14 +413,16 @@ TEST(OutputRedirectTest, ErrorInDtor) {
|
||||
std::unique_ptr<OutputRedirect> redir(new OutputRedirect(f.get()));
|
||||
// Put a character in a file buffer.
|
||||
EXPECT_EQ('x', fputc('x', f.get()));
|
||||
EXPECT_WRITE(stderr, {
|
||||
// The close function must be called inside EXPECT_WRITE, otherwise
|
||||
// the system may recycle closed file descriptor when redirecting the
|
||||
// output in EXPECT_STDERR and the second close will break output
|
||||
// redirection.
|
||||
EXPECT_WRITE(stderr,
|
||||
{
|
||||
// The close function must be called inside EXPECT_WRITE,
|
||||
// otherwise the system may recycle closed file descriptor when
|
||||
// redirecting the output in EXPECT_STDERR and the second close
|
||||
// will break output redirection.
|
||||
FMT_POSIX(close(write_fd));
|
||||
SUPPRESS_ASSERT(redir.reset(FMT_NULL));
|
||||
}, format_system_error(EBADF, "cannot flush stream"));
|
||||
},
|
||||
format_system_error(EBADF, "cannot flush stream"));
|
||||
write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,11 @@ void OutputRedirect::flush() {
|
||||
# endif
|
||||
int result = 0;
|
||||
FMT_RETRY(result, fflush(file_));
|
||||
if (result != 0)
|
||||
throw fmt::system_error(errno, "cannot flush stream");
|
||||
if (result != 0) throw fmt::system_error(errno, "cannot flush stream");
|
||||
}
|
||||
|
||||
void OutputRedirect::restore() {
|
||||
if (original_.descriptor() == -1)
|
||||
return; // Already restored.
|
||||
if (original_.descriptor() == -1) return; // Already restored.
|
||||
flush();
|
||||
// Restore the original file.
|
||||
original_.dup2(FMT_POSIX(fileno(file_)));
|
||||
@ -56,8 +54,7 @@ std::string OutputRedirect::restore_and_read() {
|
||||
|
||||
// Read everything from the pipe.
|
||||
std::string content;
|
||||
if (read_end_.descriptor() == -1)
|
||||
return content; // Already read.
|
||||
if (read_end_.descriptor() == -1) return content; // Already read.
|
||||
enum { BUFFER_SIZE = 4096 };
|
||||
char buffer[BUFFER_SIZE];
|
||||
std::size_t count = 0;
|
||||
|
@ -28,38 +28,36 @@
|
||||
bool gtest_caught_expected = false; \
|
||||
try { \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
} \
|
||||
catch (expected_exception const& e) { \
|
||||
} catch (expected_exception const& e) { \
|
||||
if (gtest_expected_message != e.what()) { \
|
||||
gtest_ar \
|
||||
<< #statement " throws an exception with a different message.\n" \
|
||||
gtest_ar << #statement \
|
||||
" throws an exception with a different message.\n" \
|
||||
<< "Expected: " << gtest_expected_message << "\n" \
|
||||
<< " Actual: " << e.what(); \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||
} \
|
||||
gtest_caught_expected = true; \
|
||||
} \
|
||||
catch (...) { \
|
||||
gtest_ar << \
|
||||
"Expected: " #statement " throws an exception of type " \
|
||||
#expected_exception ".\n Actual: it throws a different type."; \
|
||||
} catch (...) { \
|
||||
gtest_ar << "Expected: " #statement \
|
||||
" throws an exception of type " #expected_exception \
|
||||
".\n Actual: it throws a different type."; \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||
} \
|
||||
if (!gtest_caught_expected) { \
|
||||
gtest_ar << \
|
||||
"Expected: " #statement " throws an exception of type " \
|
||||
#expected_exception ".\n Actual: it throws nothing."; \
|
||||
gtest_ar << "Expected: " #statement \
|
||||
" throws an exception of type " #expected_exception \
|
||||
".\n Actual: it throws nothing."; \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||
} \
|
||||
} else \
|
||||
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
|
||||
fail(gtest_ar.failure_message())
|
||||
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
|
||||
: fail(gtest_ar.failure_message())
|
||||
|
||||
// Tests that the statement throws the expected exception and the exception's
|
||||
// what() method returns expected message.
|
||||
#define EXPECT_THROW_MSG(statement, expected_exception, expected_message) \
|
||||
FMT_TEST_THROW_(statement, expected_exception, \
|
||||
expected_message, GTEST_NONFATAL_FAILURE_)
|
||||
FMT_TEST_THROW_(statement, expected_exception, expected_message, \
|
||||
GTEST_NONFATAL_FAILURE_)
|
||||
|
||||
std::string format_system_error(int error_code, fmt::string_view message);
|
||||
|
||||
@ -99,15 +97,14 @@ class OutputRedirect {
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
std::string gtest_output = gtest_redir.restore_and_read(); \
|
||||
if (gtest_output != gtest_expected_output) { \
|
||||
gtest_ar \
|
||||
<< #statement " produces different output.\n" \
|
||||
gtest_ar << #statement " produces different output.\n" \
|
||||
<< "Expected: " << gtest_expected_output << "\n" \
|
||||
<< " Actual: " << gtest_output; \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||
} \
|
||||
} else \
|
||||
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
|
||||
fail(gtest_ar.failure_message())
|
||||
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
|
||||
: fail(gtest_ar.failure_message())
|
||||
|
||||
// Tests that the statement writes the expected output to file.
|
||||
# define EXPECT_WRITE(file, statement, expected_output) \
|
||||
@ -122,21 +119,25 @@ class SuppressAssert {
|
||||
_invalid_parameter_handler original_handler_;
|
||||
int original_report_mode_;
|
||||
|
||||
static void handle_invalid_parameter(const wchar_t *,
|
||||
const wchar_t *, const wchar_t *, unsigned , uintptr_t) {}
|
||||
static void handle_invalid_parameter(const wchar_t*, const wchar_t*,
|
||||
const wchar_t*, unsigned, uintptr_t) {}
|
||||
|
||||
public:
|
||||
SuppressAssert()
|
||||
: original_handler_(_set_invalid_parameter_handler(handle_invalid_parameter)),
|
||||
original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) {
|
||||
}
|
||||
: original_handler_(
|
||||
_set_invalid_parameter_handler(handle_invalid_parameter)),
|
||||
original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) {}
|
||||
~SuppressAssert() {
|
||||
_set_invalid_parameter_handler(original_handler_);
|
||||
_CrtSetReportMode(_CRT_ASSERT, original_report_mode_);
|
||||
}
|
||||
};
|
||||
|
||||
# define SUPPRESS_ASSERT(statement) { SuppressAssert sa; statement; }
|
||||
# define SUPPRESS_ASSERT(statement) \
|
||||
{ \
|
||||
SuppressAssert sa; \
|
||||
statement; \
|
||||
}
|
||||
# else
|
||||
# define SUPPRESS_ASSERT(statement) statement
|
||||
# endif // _MSC_VER
|
||||
@ -152,8 +153,7 @@ std::string read(fmt::file &f, std::size_t count);
|
||||
|
||||
#endif // FMT_USE_FILE_DESCRIPTORS
|
||||
|
||||
template <typename Mock>
|
||||
struct ScopedMock : testing::StrictMock<Mock> {
|
||||
template <typename Mock> struct ScopedMock : testing::StrictMock<Mock> {
|
||||
ScopedMock() { Mock::instance = this; }
|
||||
~ScopedMock() { Mock::instance = FMT_NULL; }
|
||||
};
|
||||
|
@ -8,8 +8,7 @@
|
||||
#include "fmt/locale.h"
|
||||
#include "gmock.h"
|
||||
|
||||
template <typename Char>
|
||||
struct numpunct : std::numpunct<Char> {
|
||||
template <typename Char> struct numpunct : std::numpunct<Char> {
|
||||
protected:
|
||||
Char do_thousands_sep() const FMT_OVERRIDE { return '~'; }
|
||||
};
|
||||
|
@ -8,11 +8,10 @@
|
||||
#ifndef FMT_MOCK_ALLOCATOR_H_
|
||||
#define FMT_MOCK_ALLOCATOR_H_
|
||||
|
||||
#include "gmock.h"
|
||||
#include "fmt/format.h"
|
||||
#include "gmock.h"
|
||||
|
||||
template <typename T>
|
||||
class mock_allocator {
|
||||
template <typename T> class mock_allocator {
|
||||
public:
|
||||
mock_allocator() {}
|
||||
mock_allocator(const mock_allocator&) {}
|
||||
@ -21,8 +20,7 @@ class mock_allocator {
|
||||
MOCK_METHOD2_T(deallocate, void(T* p, std::size_t n));
|
||||
};
|
||||
|
||||
template <typename Allocator>
|
||||
class allocator_ref {
|
||||
template <typename Allocator> class allocator_ref {
|
||||
private:
|
||||
Allocator* alloc_;
|
||||
|
||||
|
@ -75,20 +75,20 @@ TEST(OStreamTest, Format) {
|
||||
TEST(OStreamTest, FormatSpecs) {
|
||||
EXPECT_EQ("def ", format("{0:<5}", TestString("def")));
|
||||
EXPECT_EQ(" def", format("{0:>5}", TestString("def")));
|
||||
EXPECT_THROW_MSG(format("{0:=5}", TestString("def")),
|
||||
format_error, "format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0:=5}", TestString("def")), format_error,
|
||||
"format specifier requires numeric argument");
|
||||
EXPECT_EQ(" def ", format("{0:^5}", TestString("def")));
|
||||
EXPECT_EQ("def**", format("{0:*<5}", TestString("def")));
|
||||
EXPECT_THROW_MSG(format("{0:+}", TestString()),
|
||||
format_error, "format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0:-}", TestString()),
|
||||
format_error, "format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0: }", TestString()),
|
||||
format_error, "format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0:#}", TestString()),
|
||||
format_error, "format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0:05}", TestString()),
|
||||
format_error, "format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0:+}", TestString()), format_error,
|
||||
"format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0:-}", TestString()), format_error,
|
||||
"format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0: }", TestString()), format_error,
|
||||
"format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0:#}", TestString()), format_error,
|
||||
"format specifier requires numeric argument");
|
||||
EXPECT_THROW_MSG(format("{0:05}", TestString()), format_error,
|
||||
"format specifier requires numeric argument");
|
||||
EXPECT_EQ("test ", format("{0:13}", TestString("test")));
|
||||
EXPECT_EQ("test ", format("{0:{1}}", TestString("test"), 13));
|
||||
EXPECT_EQ("te", format("{0:.2}", TestString("test")));
|
||||
@ -125,8 +125,7 @@ TEST(OStreamTest, WriteToOStream) {
|
||||
TEST(OStreamTest, WriteToOStreamMaxSize) {
|
||||
std::size_t max_size = std::numeric_limits<std::size_t>::max();
|
||||
std::streamsize max_streamsize = std::numeric_limits<std::streamsize>::max();
|
||||
if (max_size <= fmt::internal::to_unsigned(max_streamsize))
|
||||
return;
|
||||
if (max_size <= fmt::internal::to_unsigned(max_streamsize)) return;
|
||||
|
||||
struct test_buffer : fmt::internal::buffer {
|
||||
explicit test_buffer(std::size_t size) { resize(size); }
|
||||
|
@ -13,9 +13,9 @@
|
||||
#include "posix-mock.h"
|
||||
#include "../src/posix.cc"
|
||||
|
||||
#include <climits>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <climits>
|
||||
#include <memory>
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -33,8 +33,8 @@ using fmt::error_code;
|
||||
using fmt::file;
|
||||
|
||||
using testing::_;
|
||||
using testing::StrEq;
|
||||
using testing::Return;
|
||||
using testing::StrEq;
|
||||
|
||||
namespace {
|
||||
int open_count;
|
||||
@ -53,7 +53,7 @@ std::size_t write_nbyte;
|
||||
bool sysconf_error;
|
||||
|
||||
enum FStatSimulation { NONE, MAX_SIZE, ERROR } fstat_sim;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#define EMULATE_EINTR(func, error_result) \
|
||||
if (func##_count != 0) { \
|
||||
@ -69,8 +69,8 @@ int test::open(const char *path, int oflag, int mode) {
|
||||
return ::open(path, oflag, mode);
|
||||
}
|
||||
#else
|
||||
errno_t test::sopen_s(
|
||||
int* pfh, const char *filename, int oflag, int shflag, int pmode) {
|
||||
errno_t test::sopen_s(int* pfh, const char* filename, int oflag, int shflag,
|
||||
int pmode) {
|
||||
EMULATE_EINTR(open, EINTR);
|
||||
return _sopen_s(pfh, filename, oflag, shflag, pmode);
|
||||
}
|
||||
@ -80,8 +80,7 @@ errno_t test::sopen_s(
|
||||
|
||||
long test::sysconf(int name) {
|
||||
long result = ::sysconf(name);
|
||||
if (!sysconf_error)
|
||||
return result;
|
||||
if (!sysconf_error) return result;
|
||||
// Simulate an error.
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -91,8 +90,7 @@ static off_t max_file_size() { return std::numeric_limits<off_t>::max(); }
|
||||
|
||||
int test::fstat(int fd, struct stat* buf) {
|
||||
int result = ::fstat(fd, buf);
|
||||
if (fstat_sim == MAX_SIZE)
|
||||
buf->st_size = max_file_size();
|
||||
if (fstat_sim == MAX_SIZE) buf->st_size = max_file_size();
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -208,8 +206,8 @@ TEST(UtilTest, GetPageSize) {
|
||||
#else
|
||||
EXPECT_EQ(sysconf(_SC_PAGESIZE), fmt::getpagesize());
|
||||
sysconf_error = true;
|
||||
EXPECT_SYSTEM_ERROR(
|
||||
fmt::getpagesize(), EINVAL, "cannot get memory page size");
|
||||
EXPECT_SYSTEM_ERROR(fmt::getpagesize(), EINVAL,
|
||||
"cannot get memory page size");
|
||||
sysconf_error = false;
|
||||
#endif
|
||||
}
|
||||
@ -217,8 +215,8 @@ TEST(UtilTest, GetPageSize) {
|
||||
TEST(FileTest, OpenRetry) {
|
||||
write_file("test", "there must be something here");
|
||||
std::unique_ptr<file> f{FMT_NULL};
|
||||
EXPECT_RETRY(f.reset(new file("test", file::RDONLY)),
|
||||
open, "cannot open file test");
|
||||
EXPECT_RETRY(f.reset(new file("test", file::RDONLY)), open,
|
||||
"cannot open file test");
|
||||
#ifndef _WIN32
|
||||
char c = 0;
|
||||
f->read(&c, 1);
|
||||
@ -230,12 +228,14 @@ TEST(FileTest, CloseNoRetryInDtor) {
|
||||
file::pipe(read_end, write_end);
|
||||
std::unique_ptr<file> f(new file(std::move(read_end)));
|
||||
int saved_close_count = 0;
|
||||
EXPECT_WRITE(stderr, {
|
||||
EXPECT_WRITE(stderr,
|
||||
{
|
||||
close_count = 1;
|
||||
f.reset(FMT_NULL);
|
||||
saved_close_count = close_count;
|
||||
close_count = 0;
|
||||
}, format_system_error(EINTR, "cannot close file") + "\n");
|
||||
},
|
||||
format_system_error(EINTR, "cannot close file") + "\n");
|
||||
EXPECT_EQ(2, saved_close_count);
|
||||
}
|
||||
|
||||
@ -256,8 +256,8 @@ TEST(FileTest, Size) {
|
||||
EXPECT_EQ(content.size(), static_cast<unsigned long long>(f.size()));
|
||||
#ifdef _WIN32
|
||||
fmt::memory_buffer message;
|
||||
fmt::internal::format_windows_error(
|
||||
message, ERROR_ACCESS_DENIED, "cannot get file size");
|
||||
fmt::internal::format_windows_error(message, ERROR_ACCESS_DENIED,
|
||||
"cannot get file size");
|
||||
fstat_sim = ERROR;
|
||||
EXPECT_THROW_MSG(f.size(), fmt::windows_error, fmt::to_string(message));
|
||||
fstat_sim = NONE;
|
||||
@ -284,8 +284,8 @@ TEST(FileTest, ReadRetry) {
|
||||
write_end.close();
|
||||
char buffer[SIZE];
|
||||
std::size_t count = 0;
|
||||
EXPECT_RETRY(count = read_end.read(buffer, SIZE),
|
||||
read, "cannot read from file");
|
||||
EXPECT_RETRY(count = read_end.read(buffer, SIZE), read,
|
||||
"cannot read from file");
|
||||
EXPECT_EQ_POSIX(static_cast<std::streamsize>(SIZE), count);
|
||||
}
|
||||
|
||||
@ -294,8 +294,8 @@ TEST(FileTest, WriteRetry) {
|
||||
file::pipe(read_end, write_end);
|
||||
enum { SIZE = 4 };
|
||||
std::size_t count = 0;
|
||||
EXPECT_RETRY(count = write_end.write("test", SIZE),
|
||||
write, "cannot write to file");
|
||||
EXPECT_RETRY(count = write_end.write("test", SIZE), write,
|
||||
"cannot write to file");
|
||||
write_end.close();
|
||||
#ifndef _WIN32
|
||||
EXPECT_EQ(static_cast<std::streamsize>(SIZE), count);
|
||||
@ -312,8 +312,7 @@ TEST(FileTest, ConvertReadCount) {
|
||||
file::pipe(read_end, write_end);
|
||||
char c;
|
||||
std::size_t size = UINT_MAX;
|
||||
if (sizeof(unsigned) != sizeof(std::size_t))
|
||||
++size;
|
||||
if (sizeof(unsigned) != sizeof(std::size_t)) ++size;
|
||||
read_count = 1;
|
||||
read_nbyte = 0;
|
||||
EXPECT_THROW(read_end.read(&c, size), fmt::system_error);
|
||||
@ -326,8 +325,7 @@ TEST(FileTest, ConvertWriteCount) {
|
||||
file::pipe(read_end, write_end);
|
||||
char c;
|
||||
std::size_t size = UINT_MAX;
|
||||
if (sizeof(unsigned) != sizeof(std::size_t))
|
||||
++size;
|
||||
if (sizeof(unsigned) != sizeof(std::size_t)) ++size;
|
||||
write_count = 1;
|
||||
write_nbyte = 0;
|
||||
EXPECT_THROW(write_end.write(&c, size), fmt::system_error);
|
||||
@ -339,7 +337,8 @@ TEST(FileTest, ConvertWriteCount) {
|
||||
TEST(FileTest, DupNoRetry) {
|
||||
int stdout_fd = FMT_POSIX(fileno(stdout));
|
||||
dup_count = 1;
|
||||
EXPECT_SYSTEM_ERROR(file::dup(stdout_fd), EINTR,
|
||||
EXPECT_SYSTEM_ERROR(
|
||||
file::dup(stdout_fd), EINTR,
|
||||
fmt::format("cannot duplicate file descriptor {}", stdout_fd));
|
||||
dup_count = 0;
|
||||
}
|
||||
@ -369,8 +368,8 @@ TEST(FileTest, Dup2NoExceptRetry) {
|
||||
TEST(FileTest, PipeNoRetry) {
|
||||
file read_end, write_end;
|
||||
pipe_count = 1;
|
||||
EXPECT_SYSTEM_ERROR(
|
||||
file::pipe(read_end, write_end), EINTR, "cannot create pipe");
|
||||
EXPECT_SYSTEM_ERROR(file::pipe(read_end, write_end), EINTR,
|
||||
"cannot create pipe");
|
||||
pipe_count = 0;
|
||||
}
|
||||
|
||||
@ -378,16 +377,16 @@ TEST(FileTest, FdopenNoRetry) {
|
||||
file read_end, write_end;
|
||||
file::pipe(read_end, write_end);
|
||||
fdopen_count = 1;
|
||||
EXPECT_SYSTEM_ERROR(read_end.fdopen("r"),
|
||||
EINTR, "cannot associate stream with file descriptor");
|
||||
EXPECT_SYSTEM_ERROR(read_end.fdopen("r"), EINTR,
|
||||
"cannot associate stream with file descriptor");
|
||||
fdopen_count = 0;
|
||||
}
|
||||
|
||||
TEST(BufferedFileTest, OpenRetry) {
|
||||
write_file("test", "there must be something here");
|
||||
std::unique_ptr<buffered_file> f{FMT_NULL};
|
||||
EXPECT_RETRY(f.reset(new buffered_file("test", "r")),
|
||||
fopen, "cannot open file test");
|
||||
EXPECT_RETRY(f.reset(new buffered_file("test", "r")), fopen,
|
||||
"cannot open file test");
|
||||
#ifndef _WIN32
|
||||
char c = 0;
|
||||
if (fread(&c, 1, 1, f->get()) < 1)
|
||||
@ -400,12 +399,14 @@ TEST(BufferedFileTest, CloseNoRetryInDtor) {
|
||||
file::pipe(read_end, write_end);
|
||||
std::unique_ptr<buffered_file> f(new buffered_file(read_end.fdopen("r")));
|
||||
int saved_fclose_count = 0;
|
||||
EXPECT_WRITE(stderr, {
|
||||
EXPECT_WRITE(stderr,
|
||||
{
|
||||
fclose_count = 1;
|
||||
f.reset(FMT_NULL);
|
||||
saved_fclose_count = fclose_count;
|
||||
fclose_count = 0;
|
||||
}, format_system_error(EINTR, "cannot close file") + "\n");
|
||||
},
|
||||
format_system_error(EINTR, "cannot close file") + "\n");
|
||||
EXPECT_EQ(2, saved_fclose_count);
|
||||
}
|
||||
|
||||
@ -453,8 +454,8 @@ struct LocaleMock {
|
||||
LocaleType base));
|
||||
MOCK_METHOD1(freelocale, void(LocaleType locale));
|
||||
|
||||
MOCK_METHOD3(strtod_l, double (const char *nptr, char **endptr,
|
||||
LocaleType locale));
|
||||
MOCK_METHOD3(strtod_l,
|
||||
double(const char* nptr, char** endptr, LocaleType locale));
|
||||
} * LocaleMock::instance;
|
||||
|
||||
# ifdef _MSC_VER
|
||||
@ -481,11 +482,13 @@ double _strtod_l(const char *nptr, char **endptr, _locale_t locale) {
|
||||
# define FMT_LOCALE_THROW
|
||||
# endif
|
||||
|
||||
LocaleType newlocale(int category_mask, const char *locale, LocaleType base) FMT_LOCALE_THROW {
|
||||
LocaleType newlocale(int category_mask, const char* locale,
|
||||
LocaleType base) FMT_LOCALE_THROW {
|
||||
return LocaleMock::instance->newlocale(category_mask, locale, base);
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) || (defined(__FreeBSD__) && __FreeBSD_version < 1200002)
|
||||
# if defined(__APPLE__) || \
|
||||
(defined(__FreeBSD__) && __FreeBSD_version < 1200002)
|
||||
typedef int FreeLocaleResult;
|
||||
# else
|
||||
typedef void FreeLocaleResult;
|
||||
@ -496,7 +499,8 @@ FreeLocaleResult freelocale(LocaleType locale) FMT_LOCALE_THROW {
|
||||
return FreeLocaleResult();
|
||||
}
|
||||
|
||||
double strtod_l(const char *nptr, char **endptr, LocaleType locale) FMT_LOCALE_THROW {
|
||||
double strtod_l(const char* nptr, char** endptr,
|
||||
LocaleType locale) FMT_LOCALE_THROW {
|
||||
return LocaleMock::instance->strtod_l(nptr, endptr, locale);
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,8 @@ int fstat(int fd, struct stat *buf);
|
||||
#else
|
||||
typedef unsigned size_t;
|
||||
typedef int ssize_t;
|
||||
errno_t sopen_s(
|
||||
int* pfh, const char *filename, int oflag, int shflag, int pmode);
|
||||
errno_t sopen_s(int* pfh, const char* filename, int oflag, int shflag,
|
||||
int pmode);
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
|
@ -119,14 +119,16 @@ TEST(BufferedFileTest, CloseFileInDtor) {
|
||||
|
||||
TEST(BufferedFileTest, CloseErrorInDtor) {
|
||||
std::unique_ptr<buffered_file> f(new buffered_file(open_buffered_file()));
|
||||
EXPECT_WRITE(stderr, {
|
||||
// The close function must be called inside EXPECT_WRITE, otherwise
|
||||
// the system may recycle closed file descriptor when redirecting the
|
||||
// output in EXPECT_STDERR and the second close will break output
|
||||
// redirection.
|
||||
EXPECT_WRITE(stderr,
|
||||
{
|
||||
// The close function must be called inside EXPECT_WRITE,
|
||||
// otherwise the system may recycle closed file descriptor when
|
||||
// redirecting the output in EXPECT_STDERR and the second close
|
||||
// will break output redirection.
|
||||
FMT_POSIX(close(f->fileno()));
|
||||
SUPPRESS_ASSERT(f.reset(FMT_NULL));
|
||||
}, format_system_error(EBADF, "cannot close file") + "\n");
|
||||
},
|
||||
format_system_error(EBADF, "cannot close file") + "\n");
|
||||
}
|
||||
|
||||
TEST(BufferedFileTest, Close) {
|
||||
@ -149,13 +151,15 @@ TEST(BufferedFileTest, Fileno) {
|
||||
#ifndef __COVERITY__
|
||||
// fileno on a null FILE pointer either crashes or returns an error.
|
||||
// Disable Coverity because this is intentional.
|
||||
EXPECT_DEATH_IF_SUPPORTED({
|
||||
EXPECT_DEATH_IF_SUPPORTED(
|
||||
{
|
||||
try {
|
||||
f.fileno();
|
||||
} catch (const fmt::system_error&) {
|
||||
std::exit(1);
|
||||
}
|
||||
}, "");
|
||||
},
|
||||
"");
|
||||
#endif
|
||||
f = open_buffered_file();
|
||||
EXPECT_TRUE(f.fileno() != -1);
|
||||
@ -177,8 +181,8 @@ TEST(FileTest, OpenBufferedFileInCtor) {
|
||||
}
|
||||
|
||||
TEST(FileTest, OpenBufferedFileError) {
|
||||
EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY),
|
||||
ENOENT, "cannot open file nonexistent");
|
||||
EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY), ENOENT,
|
||||
"cannot open file nonexistent");
|
||||
}
|
||||
|
||||
TEST(FileTest, MoveCtor) {
|
||||
@ -246,14 +250,16 @@ TEST(FileTest, CloseFileInDtor) {
|
||||
|
||||
TEST(FileTest, CloseErrorInDtor) {
|
||||
std::unique_ptr<file> f(new file(open_file()));
|
||||
EXPECT_WRITE(stderr, {
|
||||
// The close function must be called inside EXPECT_WRITE, otherwise
|
||||
// the system may recycle closed file descriptor when redirecting the
|
||||
// output in EXPECT_STDERR and the second close will break output
|
||||
// redirection.
|
||||
EXPECT_WRITE(stderr,
|
||||
{
|
||||
// The close function must be called inside EXPECT_WRITE,
|
||||
// otherwise the system may recycle closed file descriptor when
|
||||
// redirecting the output in EXPECT_STDERR and the second close
|
||||
// will break output redirection.
|
||||
FMT_POSIX(close(f->descriptor()));
|
||||
SUPPRESS_ASSERT(f.reset(FMT_NULL));
|
||||
}, format_system_error(EBADF, "cannot close file") + "\n");
|
||||
},
|
||||
format_system_error(EBADF, "cannot close file") + "\n");
|
||||
}
|
||||
|
||||
TEST(FileTest, Close) {
|
||||
@ -309,8 +315,8 @@ TEST(FileTest, Dup) {
|
||||
#ifndef __COVERITY__
|
||||
TEST(FileTest, DupError) {
|
||||
int value = -1;
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value),
|
||||
EBADF, "cannot duplicate file descriptor -1");
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value), EBADF,
|
||||
"cannot duplicate file descriptor -1");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -324,7 +330,8 @@ TEST(FileTest, Dup2) {
|
||||
|
||||
TEST(FileTest, Dup2Error) {
|
||||
file f = open_file();
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(f.dup2(-1), EBADF,
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(
|
||||
f.dup2(-1), EBADF,
|
||||
fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor()));
|
||||
}
|
||||
|
||||
@ -363,8 +370,8 @@ TEST(FileTest, Fdopen) {
|
||||
|
||||
TEST(FileTest, FdopenError) {
|
||||
file f;
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(
|
||||
f.fdopen("r"), EBADF, "cannot associate stream with file descriptor");
|
||||
EXPECT_SYSTEM_ERROR_NOASSERT(f.fdopen("r"), EBADF,
|
||||
"cannot associate stream with file descriptor");
|
||||
}
|
||||
|
||||
#ifdef FMT_LOCALE
|
||||
|
@ -5,6 +5,7 @@
|
||||
//
|
||||
// For the license information refer to prepare.h.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cctype>
|
||||
#include <cfloat>
|
||||
#include <climits>
|
||||
@ -13,7 +14,6 @@
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
// Check if fmt/prepare.h compiles with windows.h included before it.
|
||||
@ -303,13 +303,15 @@ TEST(PrepareTest, FormatPreparationHandler_OnArgId_AddsPartWithPassedNamedId) {
|
||||
const auto expected_third_arg_id = fmt::string_view(format.data() + 6, 3);
|
||||
const auto expected_third_arg_view_metadata =
|
||||
fmt::internal::string_view_metadata(6, 3);
|
||||
EXPECT_CALL(parts, add(format_part(
|
||||
named_argument_id(expected_first_arg_view_metadata))));
|
||||
EXPECT_CALL(
|
||||
parts,
|
||||
add(format_part(named_argument_id(expected_first_arg_view_metadata))));
|
||||
EXPECT_CALL(
|
||||
parts,
|
||||
add(format_part(named_argument_id(expected_second_arg_view_metadata))));
|
||||
EXPECT_CALL(parts, add(format_part(
|
||||
named_argument_id(expected_third_arg_view_metadata))));
|
||||
EXPECT_CALL(
|
||||
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_second_arg_id);
|
||||
|
@ -72,8 +72,7 @@ TEST(PrintfTest, PositionalArgs) {
|
||||
EXPECT_EQ("42 after", test_sprintf("%1$d after", 42));
|
||||
EXPECT_EQ("before 42 after", test_sprintf("before %1$d after", 42));
|
||||
EXPECT_EQ("answer = 42", test_sprintf("%1$s = %2$d", "answer", 42));
|
||||
EXPECT_EQ("42 is the answer",
|
||||
test_sprintf("%2$d is the %1$s", "answer", 42));
|
||||
EXPECT_EQ("42 is the answer", test_sprintf("%2$d is the %1$s", "answer", 42));
|
||||
EXPECT_EQ("abracadabra", test_sprintf("%1$s%2$s%1$s", "abra", "cad"));
|
||||
}
|
||||
|
||||
@ -82,26 +81,26 @@ TEST(PrintfTest, AutomaticArgIndexing) {
|
||||
}
|
||||
|
||||
TEST(PrintfTest, NumberIsTooBigInArgIndex) {
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$", BIG_NUM)),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM)),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$", BIG_NUM)), format_error,
|
||||
"number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM)), format_error,
|
||||
"number is too big");
|
||||
}
|
||||
|
||||
TEST(PrintfTest, SwitchArgIndexing) {
|
||||
EXPECT_THROW_MSG(test_sprintf("%1$d%", 1, 2),
|
||||
format_error, "cannot switch from manual to automatic argument indexing");
|
||||
EXPECT_THROW_MSG(test_sprintf("%1$d%", 1, 2), format_error,
|
||||
"cannot switch from manual to automatic argument indexing");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf("%1$d%d", 1, 2),
|
||||
format_error, "cannot switch from manual to automatic argument indexing");
|
||||
EXPECT_THROW_MSG(test_sprintf("%1$d%d", 1, 2), format_error,
|
||||
"cannot switch from manual to automatic argument indexing");
|
||||
|
||||
EXPECT_THROW_MSG(test_sprintf("%d%1$", 1, 2),
|
||||
format_error, "cannot switch from automatic to manual argument indexing");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%d%{}$d", BIG_NUM), 1, 2),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf("%d%1$d", 1, 2),
|
||||
format_error, "cannot switch from automatic to manual argument indexing");
|
||||
EXPECT_THROW_MSG(test_sprintf("%d%1$", 1, 2), format_error,
|
||||
"cannot switch from automatic to manual argument indexing");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%d%{}$d", BIG_NUM), 1, 2), format_error,
|
||||
"number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf("%d%1$d", 1, 2), format_error,
|
||||
"cannot switch from automatic to manual argument indexing");
|
||||
|
||||
// Indexing errors override width errors.
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%d%1${}d", BIG_NUM), 1, 2),
|
||||
@ -115,13 +114,13 @@ TEST(PrintfTest, InvalidArgIndex) {
|
||||
"argument index out of range");
|
||||
EXPECT_THROW_MSG(test_sprintf("%2$d", 42), format_error,
|
||||
"argument index out of range");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", INT_MAX), 42),
|
||||
format_error, "argument index out of range");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", INT_MAX), 42), format_error,
|
||||
"argument index out of range");
|
||||
|
||||
EXPECT_THROW_MSG(test_sprintf("%2$", 42),
|
||||
format_error, "argument index out of range");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM), 42),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf("%2$", 42), format_error,
|
||||
"argument index out of range");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM), 42), format_error,
|
||||
"number is too big");
|
||||
}
|
||||
|
||||
TEST(PrintfTest, DefaultAlignRight) {
|
||||
@ -175,8 +174,8 @@ TEST(PrintfTest, HashFlag) {
|
||||
|
||||
EXPECT_PRINTF("0x42", "%#x", 0x42);
|
||||
EXPECT_PRINTF("0X42", "%#X", 0x42);
|
||||
EXPECT_PRINTF(
|
||||
fmt::format("0x{:x}", static_cast<unsigned>(-0x42)), "%#x", -0x42);
|
||||
EXPECT_PRINTF(fmt::format("0x{:x}", static_cast<unsigned>(-0x42)), "%#x",
|
||||
-0x42);
|
||||
EXPECT_PRINTF("0", "%#x", 0);
|
||||
|
||||
EXPECT_PRINTF("0x0042", "%#06x", 0x42);
|
||||
@ -210,10 +209,10 @@ TEST(PrintfTest, Width) {
|
||||
EXPECT_THROW_MSG(test_sprintf("%5-5d", 42), format_error,
|
||||
"invalid type specifier");
|
||||
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}d", BIG_NUM), 42),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%1${}d", BIG_NUM), 42),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}d", BIG_NUM), 42), format_error,
|
||||
"number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%1${}d", BIG_NUM), 42), format_error,
|
||||
"number is too big");
|
||||
}
|
||||
|
||||
TEST(PrintfTest, DynamicWidth) {
|
||||
@ -279,12 +278,10 @@ TEST(PrintfTest, DynamicPrecision) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct make_signed { typedef T type; };
|
||||
template <typename T> struct make_signed { typedef T type; };
|
||||
|
||||
#define SPECIALIZE_MAKE_SIGNED(T, S) \
|
||||
template <> \
|
||||
struct make_signed<T> { typedef S type; }
|
||||
template <> struct make_signed<T> { typedef S type; }
|
||||
|
||||
SPECIALIZE_MAKE_SIGNED(char, signed char);
|
||||
SPECIALIZE_MAKE_SIGNED(unsigned char, signed char);
|
||||
@ -335,8 +332,7 @@ void TestLength(const char *length_spec, U value) {
|
||||
EXPECT_PRINTF(os.str(), fmt::format("%{}X", length_spec), value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void TestLength(const char *length_spec) {
|
||||
template <typename T> void TestLength(const char* length_spec) {
|
||||
T min = std::numeric_limits<T>::min(), max = std::numeric_limits<T>::max();
|
||||
TestLength<T>(length_spec, 42);
|
||||
TestLength<T>(length_spec, -42);
|
||||
@ -475,9 +471,7 @@ TEST(PrintfTest, Location) {
|
||||
|
||||
enum E { A = 42 };
|
||||
|
||||
TEST(PrintfTest, Enum) {
|
||||
EXPECT_PRINTF("42", "%d", A);
|
||||
}
|
||||
TEST(PrintfTest, Enum) { EXPECT_PRINTF("42", "%d", A); }
|
||||
|
||||
#if FMT_USE_FILE_DESCRIPTORS
|
||||
TEST(PrintfTest, Examples) {
|
||||
@ -496,9 +490,7 @@ TEST(PrintfTest, PrintfError) {
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(PrintfTest, WideString) {
|
||||
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc"));
|
||||
}
|
||||
TEST(PrintfTest, WideString) { EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc")); }
|
||||
|
||||
TEST(PrintfTest, PrintfCustom) {
|
||||
EXPECT_EQ("abc", test_sprintf("%s", TestString("abc")));
|
||||
@ -530,21 +522,19 @@ TEST(PrintfTest, CheckFormatStringRegression) {
|
||||
}
|
||||
|
||||
TEST(PrintfTest, VSPrintfMakeArgsExample) {
|
||||
fmt::format_arg_store<fmt::printf_context, int, const char *> as{
|
||||
42, "something"};
|
||||
fmt::format_arg_store<fmt::printf_context, int, const char*> as{42,
|
||||
"something"};
|
||||
fmt::basic_format_args<fmt::printf_context> args(as);
|
||||
EXPECT_EQ(
|
||||
"[42] something happened", fmt::vsprintf("[%d] %s happened", args));
|
||||
EXPECT_EQ("[42] something happened", fmt::vsprintf("[%d] %s happened", args));
|
||||
auto as2 = fmt::make_printf_args(42, "something");
|
||||
fmt::basic_format_args<fmt::printf_context> args2(as2);
|
||||
EXPECT_EQ(
|
||||
"[42] something happened", fmt::vsprintf("[%d] %s happened", args2));
|
||||
EXPECT_EQ("[42] something happened",
|
||||
fmt::vsprintf("[%d] %s happened", args2));
|
||||
// the older gcc versions can't cast the return value
|
||||
#if !defined(__GNUC__) || (__GNUC__ > 4)
|
||||
EXPECT_EQ(
|
||||
"[42] something happened",
|
||||
fmt::vsprintf(
|
||||
"[%d] %s happened", fmt::make_printf_args(42, "something")));
|
||||
EXPECT_EQ("[42] something happened",
|
||||
fmt::vsprintf("[%d] %s happened",
|
||||
fmt::make_printf_args(42, "something")));
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -552,18 +542,16 @@ TEST(PrintfTest, VSPrintfMakeWArgsExample) {
|
||||
fmt::format_arg_store<fmt::wprintf_context, int, const wchar_t*> as{
|
||||
42, L"something"};
|
||||
fmt::basic_format_args<fmt::wprintf_context> args(as);
|
||||
EXPECT_EQ(
|
||||
L"[42] something happened",
|
||||
EXPECT_EQ(L"[42] something happened",
|
||||
fmt::vsprintf(L"[%d] %s happened", args));
|
||||
auto as2 = fmt::make_wprintf_args(42, L"something");
|
||||
fmt::basic_format_args<fmt::wprintf_context> args2(as2);
|
||||
EXPECT_EQ(
|
||||
L"[42] something happened", fmt::vsprintf(L"[%d] %s happened", args2));
|
||||
EXPECT_EQ(L"[42] something happened",
|
||||
fmt::vsprintf(L"[%d] %s happened", args2));
|
||||
// the older gcc versions can't cast the return value
|
||||
#if !defined(__GNUC__) || (__GNUC__ > 4)
|
||||
EXPECT_EQ(
|
||||
L"[42] something happened",
|
||||
fmt::vsprintf(
|
||||
L"[%d] %s happened", fmt::make_wprintf_args(42, L"something")));
|
||||
EXPECT_EQ(L"[42] something happened",
|
||||
fmt::vsprintf(L"[%d] %s happened",
|
||||
fmt::make_wprintf_args(42, L"something")));
|
||||
#endif
|
||||
}
|
||||
|
@ -16,10 +16,10 @@
|
||||
# include "fmt/ranges.h"
|
||||
# include "gtest.h"
|
||||
|
||||
#include <vector>
|
||||
# include <array>
|
||||
# include <map>
|
||||
# include <string>
|
||||
# include <vector>
|
||||
|
||||
TEST(RangesTest, FormatVector) {
|
||||
std::vector<int32_t> iv{1, 2, 3, 5, 7, 11};
|
||||
@ -52,8 +52,7 @@ TEST(RangesTest, FormatTuple) {
|
||||
struct my_struct {
|
||||
int32_t i;
|
||||
std::string str; // can throw
|
||||
template <std::size_t N>
|
||||
decltype(auto) get() const noexcept {
|
||||
template <std::size_t N> decltype(auto) get() const noexcept {
|
||||
if constexpr (N == 0)
|
||||
return i;
|
||||
else if constexpr (N == 1)
|
||||
@ -61,8 +60,7 @@ struct my_struct {
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
decltype(auto) get(const my_struct& s) noexcept {
|
||||
template <std::size_t N> decltype(auto) get(const my_struct& s) noexcept {
|
||||
return s.get<N>();
|
||||
}
|
||||
|
||||
@ -71,8 +69,7 @@ namespace std {
|
||||
template <>
|
||||
struct tuple_size<my_struct> : std::integral_constant<std::size_t, 2> {};
|
||||
|
||||
template <std::size_t N>
|
||||
struct tuple_element<N, my_struct> {
|
||||
template <std::size_t N> struct tuple_element<N, my_struct> {
|
||||
using type = decltype(std::declval<my_struct>().get<N>());
|
||||
};
|
||||
|
||||
|
@ -9,9 +9,9 @@
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "gmock.h"
|
||||
#include "fmt/locale.h"
|
||||
#include "fmt/time.h"
|
||||
#include "fmt/locale.h"
|
||||
#include "gmock.h"
|
||||
|
||||
TEST(TimeTest, Format) {
|
||||
std::tm tm = std::tm();
|
||||
@ -24,8 +24,7 @@ TEST(TimeTest, Format) {
|
||||
|
||||
TEST(TimeTest, GrowBuffer) {
|
||||
std::string s = "{:";
|
||||
for (int i = 0; i < 30; ++i)
|
||||
s += "%c";
|
||||
for (int i = 0; i < 30; ++i) s += "%c";
|
||||
s += "}\n";
|
||||
std::time_t t = std::time(FMT_NULL);
|
||||
fmt::format(s, *std::localtime(&t));
|
||||
@ -39,19 +38,13 @@ TEST(TimeTest, FormatToEmptyContainer) {
|
||||
EXPECT_EQ(s, "42");
|
||||
}
|
||||
|
||||
TEST(TimeTest, EmptyResult) {
|
||||
EXPECT_EQ("", fmt::format("{}", std::tm()));
|
||||
}
|
||||
TEST(TimeTest, EmptyResult) { EXPECT_EQ("", fmt::format("{}", std::tm())); }
|
||||
|
||||
static bool EqualTime(const std::tm& lhs, const std::tm& rhs) {
|
||||
return lhs.tm_sec == rhs.tm_sec &&
|
||||
lhs.tm_min == rhs.tm_min &&
|
||||
lhs.tm_hour == rhs.tm_hour &&
|
||||
lhs.tm_mday == rhs.tm_mday &&
|
||||
lhs.tm_mon == rhs.tm_mon &&
|
||||
lhs.tm_year == rhs.tm_year &&
|
||||
lhs.tm_wday == rhs.tm_wday &&
|
||||
lhs.tm_yday == rhs.tm_yday &&
|
||||
return lhs.tm_sec == rhs.tm_sec && lhs.tm_min == rhs.tm_min &&
|
||||
lhs.tm_hour == rhs.tm_hour && lhs.tm_mday == rhs.tm_mday &&
|
||||
lhs.tm_mon == rhs.tm_mon && lhs.tm_year == rhs.tm_year &&
|
||||
lhs.tm_wday == rhs.tm_wday && lhs.tm_yday == rhs.tm_yday &&
|
||||
lhs.tm_isdst == rhs.tm_isdst;
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,6 @@ fmt::buffered_file open_buffered_file(FILE **fp) {
|
||||
write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT));
|
||||
write_end.close();
|
||||
fmt::buffered_file f = read_end.fdopen("r");
|
||||
if (fp)
|
||||
*fp = f.get();
|
||||
if (fp) *fp = f.get();
|
||||
return f;
|
||||
}
|
||||
|
11
test/util.h
11
test/util.h
@ -48,8 +48,7 @@ inline FILE *safe_fopen(const char *filename, const char *mode) {
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
class BasicTestString {
|
||||
template <typename Char> class BasicTestString {
|
||||
private:
|
||||
std::basic_string<Char> value_;
|
||||
|
||||
@ -61,21 +60,21 @@ class BasicTestString {
|
||||
const std::basic_string<Char>& value() const { return value_; }
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
const Char BasicTestString<Char>::EMPTY[] = {0};
|
||||
template <typename Char> const Char BasicTestString<Char>::EMPTY[] = {0};
|
||||
|
||||
typedef BasicTestString<char> TestString;
|
||||
typedef BasicTestString<wchar_t> TestWString;
|
||||
|
||||
template <typename Char>
|
||||
std::basic_ostream<Char> &operator<<(
|
||||
std::basic_ostream<Char> &os, const BasicTestString<Char> &s) {
|
||||
std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& os,
|
||||
const BasicTestString<Char>& s) {
|
||||
os << s.value();
|
||||
return os;
|
||||
}
|
||||
|
||||
class Date {
|
||||
int year_, month_, day_;
|
||||
|
||||
public:
|
||||
Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user