mirror of
https://github.com/gabime/spdlog.git
synced 2024-12-25 18:11:33 +08:00
Bumped fmt to version 5.3.0
This commit is contained in:
parent
0955ea5b85
commit
2ac42c0d14
452
include/spdlog/fmt/bundled/chrono.h
Normal file
452
include/spdlog/fmt/bundled/chrono.h
Normal file
@ -0,0 +1,452 @@
|
|||||||
|
// Formatting library for C++ - chrono support
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_CHRONO_H_
|
||||||
|
#define FMT_CHRONO_H_
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
#include "locale.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <ctime>
|
||||||
|
#include <locale>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace internal{
|
||||||
|
|
||||||
|
enum class numeric_system {
|
||||||
|
standard,
|
||||||
|
// Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale.
|
||||||
|
alternative
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
auto ptr = begin;
|
||||||
|
while (ptr != end) {
|
||||||
|
auto c = *ptr;
|
||||||
|
if (c == '}') break;
|
||||||
|
if (c != '%') {
|
||||||
|
++ptr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (begin != ptr)
|
||||||
|
handler.on_text(begin, ptr);
|
||||||
|
++ptr; // consume '%'
|
||||||
|
if (ptr == end)
|
||||||
|
throw format_error("invalid format");
|
||||||
|
c = *ptr++;
|
||||||
|
switch (c) {
|
||||||
|
case '%':
|
||||||
|
handler.on_text(ptr - 1, ptr);
|
||||||
|
break;
|
||||||
|
case 'n': {
|
||||||
|
const char newline[] = "\n";
|
||||||
|
handler.on_text(newline, newline + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 't': {
|
||||||
|
const char tab[] = "\t";
|
||||||
|
handler.on_text(tab, tab + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Day of the week:
|
||||||
|
case 'a':
|
||||||
|
handler.on_abbr_weekday();
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
handler.on_full_weekday();
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
handler.on_dec0_weekday(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
handler.on_dec1_weekday(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
// Month:
|
||||||
|
case 'b':
|
||||||
|
handler.on_abbr_month();
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
handler.on_full_month();
|
||||||
|
break;
|
||||||
|
// Hour, minute, second:
|
||||||
|
case 'H':
|
||||||
|
handler.on_24_hour(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
handler.on_12_hour(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
handler.on_minute(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
handler.on_second(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
// Other:
|
||||||
|
case 'c':
|
||||||
|
handler.on_datetime(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
handler.on_loc_date(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
handler.on_loc_time(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
handler.on_us_date();
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
handler.on_iso_date();
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
handler.on_12_hour_time();
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
handler.on_24_hour_time();
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
handler.on_iso_time();
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
handler.on_am_pm();
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
handler.on_utc_offset();
|
||||||
|
break;
|
||||||
|
case 'Z':
|
||||||
|
handler.on_tz_name();
|
||||||
|
break;
|
||||||
|
// Alternative representation:
|
||||||
|
case 'E': {
|
||||||
|
if (ptr == end)
|
||||||
|
throw format_error("invalid format");
|
||||||
|
c = *ptr++;
|
||||||
|
switch (c) {
|
||||||
|
case 'c':
|
||||||
|
handler.on_datetime(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
handler.on_loc_date(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
handler.on_loc_time(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw format_error("invalid format");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'O':
|
||||||
|
if (ptr == end)
|
||||||
|
throw format_error("invalid format");
|
||||||
|
c = *ptr++;
|
||||||
|
switch (c) {
|
||||||
|
case 'w':
|
||||||
|
handler.on_dec0_weekday(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
handler.on_dec1_weekday(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
handler.on_24_hour(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
handler.on_12_hour(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
handler.on_minute(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
handler.on_second(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw format_error("invalid format");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw format_error("invalid format");
|
||||||
|
}
|
||||||
|
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 *) {}
|
||||||
|
void on_abbr_weekday() { report_no_date(); }
|
||||||
|
void on_full_weekday() { report_no_date(); }
|
||||||
|
void on_dec0_weekday(numeric_system) { report_no_date(); }
|
||||||
|
void on_dec1_weekday(numeric_system) { report_no_date(); }
|
||||||
|
void on_abbr_month() { report_no_date(); }
|
||||||
|
void on_full_month() { report_no_date(); }
|
||||||
|
void on_24_hour(numeric_system) {}
|
||||||
|
void on_12_hour(numeric_system) {}
|
||||||
|
void on_minute(numeric_system) {}
|
||||||
|
void on_second(numeric_system) {}
|
||||||
|
void on_datetime(numeric_system) { report_no_date(); }
|
||||||
|
void on_loc_date(numeric_system) { report_no_date(); }
|
||||||
|
void on_loc_time(numeric_system) { report_no_date(); }
|
||||||
|
void on_us_date() { report_no_date(); }
|
||||||
|
void on_iso_date() { report_no_date(); }
|
||||||
|
void on_12_hour_time() {}
|
||||||
|
void on_24_hour_time() {}
|
||||||
|
void on_iso_time() {}
|
||||||
|
void on_am_pm() {}
|
||||||
|
void on_utc_offset() { report_no_date(); }
|
||||||
|
void on_tz_name() { report_no_date(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
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");
|
||||||
|
return static_cast<int>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext, typename OutputIt>
|
||||||
|
struct chrono_formatter {
|
||||||
|
FormatContext &context;
|
||||||
|
OutputIt out;
|
||||||
|
std::chrono::seconds s;
|
||||||
|
std::chrono::milliseconds ms;
|
||||||
|
|
||||||
|
typedef typename FormatContext::char_type char_type;
|
||||||
|
|
||||||
|
explicit chrono_formatter(FormatContext &ctx, OutputIt o)
|
||||||
|
: context(ctx), out(o) {}
|
||||||
|
|
||||||
|
int hour() const { return to_int((s.count() / 3600) % 24); }
|
||||||
|
|
||||||
|
int hour12() const {
|
||||||
|
auto hour = to_int((s.count() / 3600) % 12);
|
||||||
|
return hour > 0 ? hour : 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minute() const { return to_int((s.count() / 60) % 60); }
|
||||||
|
int second() const { return to_int(s.count() % 60); }
|
||||||
|
|
||||||
|
std::tm time() const {
|
||||||
|
auto time = std::tm();
|
||||||
|
time.tm_hour = hour();
|
||||||
|
time.tm_min = minute();
|
||||||
|
time.tm_sec = second();
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(int value, int width) {
|
||||||
|
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');
|
||||||
|
out = format_decimal<char_type>(out, n, num_digits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void format_localized(const tm &time, const char *format) {
|
||||||
|
auto locale = context.locale().template get<std::locale>();
|
||||||
|
auto &facet = std::use_facet<std::time_put<char_type>>(locale);
|
||||||
|
std::basic_ostringstream<char_type> os;
|
||||||
|
os.imbue(locale);
|
||||||
|
facet.put(os, os, ' ', &time, format, format + std::strlen(format));
|
||||||
|
auto str = os.str();
|
||||||
|
std::copy(str.begin(), str.end(), out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_text(const char_type *begin, const char_type *end) {
|
||||||
|
std::copy(begin, end, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are not implemented because durations don't have date information.
|
||||||
|
void on_abbr_weekday() {}
|
||||||
|
void on_full_weekday() {}
|
||||||
|
void on_dec0_weekday(numeric_system) {}
|
||||||
|
void on_dec1_weekday(numeric_system) {}
|
||||||
|
void on_abbr_month() {}
|
||||||
|
void on_full_month() {}
|
||||||
|
void on_datetime(numeric_system) {}
|
||||||
|
void on_loc_date(numeric_system) {}
|
||||||
|
void on_loc_time(numeric_system) {}
|
||||||
|
void on_us_date() {}
|
||||||
|
void on_iso_date() {}
|
||||||
|
void on_utc_offset() {}
|
||||||
|
void on_tz_name() {}
|
||||||
|
|
||||||
|
void on_24_hour(numeric_system ns) {
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
auto time = tm();
|
||||||
|
time.tm_min = minute();
|
||||||
|
format_localized(time, "%OM");
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_second(numeric_system ns) {
|
||||||
|
if (ns == numeric_system::standard) {
|
||||||
|
write(second(), 2);
|
||||||
|
if (ms != std::chrono::milliseconds(0)) {
|
||||||
|
*out++ = '.';
|
||||||
|
write(to_int(ms.count()), 3);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto time = tm();
|
||||||
|
time.tm_sec = second();
|
||||||
|
format_localized(time, "%OS");
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_12_hour_time() { format_localized(time(), "%r"); }
|
||||||
|
|
||||||
|
void on_24_hour_time() {
|
||||||
|
write(hour(), 2);
|
||||||
|
*out++ = ':';
|
||||||
|
write(minute(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_iso_time() {
|
||||||
|
on_24_hour_time();
|
||||||
|
*out++ = ':';
|
||||||
|
write(second(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_am_pm() { format_localized(time(), "%p"); }
|
||||||
|
};
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
template <typename Period> FMT_CONSTEXPR const char *get_units() {
|
||||||
|
return FMT_NULL;
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::atto>() { return "as"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::femto>() { return "fs"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::pico>() { return "ps"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::nano>() { return "ns"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::micro>() { return "µs"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::milli>() { return "ms"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::centi>() { return "cs"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::deci>() { return "ds"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::ratio<1>>() { return "s"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::deca>() { return "das"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::hecto>() { return "hs"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::kilo>() { return "ks"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::mega>() { return "Ms"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::giga>() { return "Gs"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::tera>() { return "Ts"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::peta>() { return "Ps"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::exa>() { return "Es"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::ratio<60>>() {
|
||||||
|
return "m";
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::ratio<3600>>() {
|
||||||
|
return "h";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Rep, typename Period, typename Char>
|
||||||
|
struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||||
|
private:
|
||||||
|
align_spec spec;
|
||||||
|
internal::arg_ref<Char> width_ref;
|
||||||
|
mutable basic_string_view<Char> format_str;
|
||||||
|
typedef std::chrono::duration<Rep, Period> duration;
|
||||||
|
|
||||||
|
struct spec_handler {
|
||||||
|
formatter &f;
|
||||||
|
basic_parse_context<Char> &context;
|
||||||
|
|
||||||
|
typedef internal::arg_ref<Char> arg_ref_type;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {
|
||||||
|
return arg_ref_type(context.next_arg_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_error(const char *msg) { throw format_error(msg); }
|
||||||
|
void on_fill(Char fill) { f.spec.fill_ = fill; }
|
||||||
|
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) {
|
||||||
|
f.width_ref = make_arg_ref(arg_id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
formatter() : spec() {}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR auto parse(basic_parse_context<Char> &ctx)
|
||||||
|
-> decltype(ctx.begin()) {
|
||||||
|
auto begin = ctx.begin(), end = ctx.end();
|
||||||
|
if (begin == end) return begin;
|
||||||
|
spec_handler handler{*this, ctx};
|
||||||
|
begin = internal::parse_align(begin, end, handler);
|
||||||
|
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));
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const duration &d, FormatContext &ctx)
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto begin = format_str.begin(), end = format_str.end();
|
||||||
|
memory_buffer buf;
|
||||||
|
typedef output_range<decltype(ctx.out()), Char> range;
|
||||||
|
basic_writer<range> w(range(ctx.out()));
|
||||||
|
if (begin == end || *begin == '}') {
|
||||||
|
if (const char *unit = get_units<Period>())
|
||||||
|
format_to(buf, "{}{}", d.count(), unit);
|
||||||
|
else if (Period::den == 1)
|
||||||
|
format_to(buf, "{}[{}]s", d.count(), Period::num);
|
||||||
|
else
|
||||||
|
format_to(buf, "{}[{}/{}]s", d.count(), Period::num, Period::den);
|
||||||
|
internal::handle_dynamic_spec<internal::width_checker>(
|
||||||
|
spec.width_, width_ref, ctx);
|
||||||
|
} else {
|
||||||
|
auto out = std::back_inserter(buf);
|
||||||
|
internal::chrono_formatter<FormatContext, decltype(out)> f(ctx, out);
|
||||||
|
f.s = std::chrono::duration_cast<std::chrono::seconds>(d);
|
||||||
|
f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s);
|
||||||
|
parse_chrono_format(begin, end, f);
|
||||||
|
}
|
||||||
|
w.write(buf.data(), buf.size(), spec);
|
||||||
|
return w.out();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_CHRONO_H_
|
577
include/spdlog/fmt/bundled/color.h
Normal file
577
include/spdlog/fmt/bundled/color.h
Normal file
@ -0,0 +1,577 @@
|
|||||||
|
// Formatting library for C++ - color support
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_COLOR_H_
|
||||||
|
#define FMT_COLOR_H_
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef FMT_DEPRECATED_COLORS
|
||||||
|
|
||||||
|
// color and (v)print_colored are deprecated.
|
||||||
|
enum color { black, red, green, yellow, blue, magenta, cyan, white };
|
||||||
|
FMT_API void vprint_colored(color c, string_view format, format_args args);
|
||||||
|
FMT_API void vprint_colored(color c, wstring_view format, wformat_args args);
|
||||||
|
template <typename... Args>
|
||||||
|
inline void print_colored(color c, string_view format_str,
|
||||||
|
const Args & ... args) {
|
||||||
|
vprint_colored(c, format_str, make_format_args(args...));
|
||||||
|
}
|
||||||
|
template <typename... Args>
|
||||||
|
inline void print_colored(color c, wstring_view format_str,
|
||||||
|
const Args & ... args) {
|
||||||
|
vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void vprint_colored(color c, string_view format, format_args args) {
|
||||||
|
char escape[] = "\x1b[30m";
|
||||||
|
escape[3] = static_cast<char>('0' + c);
|
||||||
|
std::fputs(escape, stdout);
|
||||||
|
vprint(format, args);
|
||||||
|
std::fputs(internal::data::RESET_COLOR, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void vprint_colored(color c, wstring_view format, wformat_args args) {
|
||||||
|
wchar_t escape[] = L"\x1b[30m";
|
||||||
|
escape[3] = static_cast<wchar_t>('0' + c);
|
||||||
|
std::fputws(escape, stdout);
|
||||||
|
vprint(format, args);
|
||||||
|
std::fputws(internal::data::WRESET_COLOR, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
enum class color : uint32_t {
|
||||||
|
alice_blue = 0xF0F8FF, // rgb(240,248,255)
|
||||||
|
antique_white = 0xFAEBD7, // rgb(250,235,215)
|
||||||
|
aqua = 0x00FFFF, // rgb(0,255,255)
|
||||||
|
aquamarine = 0x7FFFD4, // rgb(127,255,212)
|
||||||
|
azure = 0xF0FFFF, // rgb(240,255,255)
|
||||||
|
beige = 0xF5F5DC, // rgb(245,245,220)
|
||||||
|
bisque = 0xFFE4C4, // rgb(255,228,196)
|
||||||
|
black = 0x000000, // rgb(0,0,0)
|
||||||
|
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
|
||||||
|
blue = 0x0000FF, // rgb(0,0,255)
|
||||||
|
blue_violet = 0x8A2BE2, // rgb(138,43,226)
|
||||||
|
brown = 0xA52A2A, // rgb(165,42,42)
|
||||||
|
burly_wood = 0xDEB887, // rgb(222,184,135)
|
||||||
|
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
|
||||||
|
chartreuse = 0x7FFF00, // rgb(127,255,0)
|
||||||
|
chocolate = 0xD2691E, // rgb(210,105,30)
|
||||||
|
coral = 0xFF7F50, // rgb(255,127,80)
|
||||||
|
cornflower_blue = 0x6495ED, // rgb(100,149,237)
|
||||||
|
cornsilk = 0xFFF8DC, // rgb(255,248,220)
|
||||||
|
crimson = 0xDC143C, // rgb(220,20,60)
|
||||||
|
cyan = 0x00FFFF, // rgb(0,255,255)
|
||||||
|
dark_blue = 0x00008B, // rgb(0,0,139)
|
||||||
|
dark_cyan = 0x008B8B, // rgb(0,139,139)
|
||||||
|
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
|
||||||
|
dark_gray = 0xA9A9A9, // rgb(169,169,169)
|
||||||
|
dark_green = 0x006400, // rgb(0,100,0)
|
||||||
|
dark_khaki = 0xBDB76B, // rgb(189,183,107)
|
||||||
|
dark_magenta = 0x8B008B, // rgb(139,0,139)
|
||||||
|
dark_olive_green = 0x556B2F, // rgb(85,107,47)
|
||||||
|
dark_orange = 0xFF8C00, // rgb(255,140,0)
|
||||||
|
dark_orchid = 0x9932CC, // rgb(153,50,204)
|
||||||
|
dark_red = 0x8B0000, // rgb(139,0,0)
|
||||||
|
dark_salmon = 0xE9967A, // rgb(233,150,122)
|
||||||
|
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
|
||||||
|
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
|
||||||
|
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
|
||||||
|
dark_turquoise = 0x00CED1, // rgb(0,206,209)
|
||||||
|
dark_violet = 0x9400D3, // rgb(148,0,211)
|
||||||
|
deep_pink = 0xFF1493, // rgb(255,20,147)
|
||||||
|
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
|
||||||
|
dim_gray = 0x696969, // rgb(105,105,105)
|
||||||
|
dodger_blue = 0x1E90FF, // rgb(30,144,255)
|
||||||
|
fire_brick = 0xB22222, // rgb(178,34,34)
|
||||||
|
floral_white = 0xFFFAF0, // rgb(255,250,240)
|
||||||
|
forest_green = 0x228B22, // rgb(34,139,34)
|
||||||
|
fuchsia = 0xFF00FF, // rgb(255,0,255)
|
||||||
|
gainsboro = 0xDCDCDC, // rgb(220,220,220)
|
||||||
|
ghost_white = 0xF8F8FF, // rgb(248,248,255)
|
||||||
|
gold = 0xFFD700, // rgb(255,215,0)
|
||||||
|
golden_rod = 0xDAA520, // rgb(218,165,32)
|
||||||
|
gray = 0x808080, // rgb(128,128,128)
|
||||||
|
green = 0x008000, // rgb(0,128,0)
|
||||||
|
green_yellow = 0xADFF2F, // rgb(173,255,47)
|
||||||
|
honey_dew = 0xF0FFF0, // rgb(240,255,240)
|
||||||
|
hot_pink = 0xFF69B4, // rgb(255,105,180)
|
||||||
|
indian_red = 0xCD5C5C, // rgb(205,92,92)
|
||||||
|
indigo = 0x4B0082, // rgb(75,0,130)
|
||||||
|
ivory = 0xFFFFF0, // rgb(255,255,240)
|
||||||
|
khaki = 0xF0E68C, // rgb(240,230,140)
|
||||||
|
lavender = 0xE6E6FA, // rgb(230,230,250)
|
||||||
|
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
|
||||||
|
lawn_green = 0x7CFC00, // rgb(124,252,0)
|
||||||
|
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
|
||||||
|
light_blue = 0xADD8E6, // rgb(173,216,230)
|
||||||
|
light_coral = 0xF08080, // rgb(240,128,128)
|
||||||
|
light_cyan = 0xE0FFFF, // rgb(224,255,255)
|
||||||
|
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
|
||||||
|
light_gray = 0xD3D3D3, // rgb(211,211,211)
|
||||||
|
light_green = 0x90EE90, // rgb(144,238,144)
|
||||||
|
light_pink = 0xFFB6C1, // rgb(255,182,193)
|
||||||
|
light_salmon = 0xFFA07A, // rgb(255,160,122)
|
||||||
|
light_sea_green = 0x20B2AA, // rgb(32,178,170)
|
||||||
|
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
|
||||||
|
light_slate_gray = 0x778899, // rgb(119,136,153)
|
||||||
|
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
|
||||||
|
light_yellow = 0xFFFFE0, // rgb(255,255,224)
|
||||||
|
lime = 0x00FF00, // rgb(0,255,0)
|
||||||
|
lime_green = 0x32CD32, // rgb(50,205,50)
|
||||||
|
linen = 0xFAF0E6, // rgb(250,240,230)
|
||||||
|
magenta = 0xFF00FF, // rgb(255,0,255)
|
||||||
|
maroon = 0x800000, // rgb(128,0,0)
|
||||||
|
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
|
||||||
|
medium_blue = 0x0000CD, // rgb(0,0,205)
|
||||||
|
medium_orchid = 0xBA55D3, // rgb(186,85,211)
|
||||||
|
medium_purple = 0x9370DB, // rgb(147,112,219)
|
||||||
|
medium_sea_green = 0x3CB371, // rgb(60,179,113)
|
||||||
|
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
|
||||||
|
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
|
||||||
|
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
|
||||||
|
medium_violet_red = 0xC71585, // rgb(199,21,133)
|
||||||
|
midnight_blue = 0x191970, // rgb(25,25,112)
|
||||||
|
mint_cream = 0xF5FFFA, // rgb(245,255,250)
|
||||||
|
misty_rose = 0xFFE4E1, // rgb(255,228,225)
|
||||||
|
moccasin = 0xFFE4B5, // rgb(255,228,181)
|
||||||
|
navajo_white = 0xFFDEAD, // rgb(255,222,173)
|
||||||
|
navy = 0x000080, // rgb(0,0,128)
|
||||||
|
old_lace = 0xFDF5E6, // rgb(253,245,230)
|
||||||
|
olive = 0x808000, // rgb(128,128,0)
|
||||||
|
olive_drab = 0x6B8E23, // rgb(107,142,35)
|
||||||
|
orange = 0xFFA500, // rgb(255,165,0)
|
||||||
|
orange_red = 0xFF4500, // rgb(255,69,0)
|
||||||
|
orchid = 0xDA70D6, // rgb(218,112,214)
|
||||||
|
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
|
||||||
|
pale_green = 0x98FB98, // rgb(152,251,152)
|
||||||
|
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
|
||||||
|
pale_violet_red = 0xDB7093, // rgb(219,112,147)
|
||||||
|
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
|
||||||
|
peach_puff = 0xFFDAB9, // rgb(255,218,185)
|
||||||
|
peru = 0xCD853F, // rgb(205,133,63)
|
||||||
|
pink = 0xFFC0CB, // rgb(255,192,203)
|
||||||
|
plum = 0xDDA0DD, // rgb(221,160,221)
|
||||||
|
powder_blue = 0xB0E0E6, // rgb(176,224,230)
|
||||||
|
purple = 0x800080, // rgb(128,0,128)
|
||||||
|
rebecca_purple = 0x663399, // rgb(102,51,153)
|
||||||
|
red = 0xFF0000, // rgb(255,0,0)
|
||||||
|
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
|
||||||
|
royal_blue = 0x4169E1, // rgb(65,105,225)
|
||||||
|
saddle_brown = 0x8B4513, // rgb(139,69,19)
|
||||||
|
salmon = 0xFA8072, // rgb(250,128,114)
|
||||||
|
sandy_brown = 0xF4A460, // rgb(244,164,96)
|
||||||
|
sea_green = 0x2E8B57, // rgb(46,139,87)
|
||||||
|
sea_shell = 0xFFF5EE, // rgb(255,245,238)
|
||||||
|
sienna = 0xA0522D, // rgb(160,82,45)
|
||||||
|
silver = 0xC0C0C0, // rgb(192,192,192)
|
||||||
|
sky_blue = 0x87CEEB, // rgb(135,206,235)
|
||||||
|
slate_blue = 0x6A5ACD, // rgb(106,90,205)
|
||||||
|
slate_gray = 0x708090, // rgb(112,128,144)
|
||||||
|
snow = 0xFFFAFA, // rgb(255,250,250)
|
||||||
|
spring_green = 0x00FF7F, // rgb(0,255,127)
|
||||||
|
steel_blue = 0x4682B4, // rgb(70,130,180)
|
||||||
|
tan = 0xD2B48C, // rgb(210,180,140)
|
||||||
|
teal = 0x008080, // rgb(0,128,128)
|
||||||
|
thistle = 0xD8BFD8, // rgb(216,191,216)
|
||||||
|
tomato = 0xFF6347, // rgb(255,99,71)
|
||||||
|
turquoise = 0x40E0D0, // rgb(64,224,208)
|
||||||
|
violet = 0xEE82EE, // rgb(238,130,238)
|
||||||
|
wheat = 0xF5DEB3, // rgb(245,222,179)
|
||||||
|
white = 0xFFFFFF, // rgb(255,255,255)
|
||||||
|
white_smoke = 0xF5F5F5, // rgb(245,245,245)
|
||||||
|
yellow = 0xFFFF00, // rgb(255,255,0)
|
||||||
|
yellow_green = 0x9ACD32 // rgb(154,205,50)
|
||||||
|
}; // enum class color
|
||||||
|
|
||||||
|
enum class terminal_color : uint8_t {
|
||||||
|
black = 30,
|
||||||
|
red,
|
||||||
|
green,
|
||||||
|
yellow,
|
||||||
|
blue,
|
||||||
|
magenta,
|
||||||
|
cyan,
|
||||||
|
white,
|
||||||
|
bright_black = 90,
|
||||||
|
bright_red,
|
||||||
|
bright_green,
|
||||||
|
bright_yellow,
|
||||||
|
bright_blue,
|
||||||
|
bright_magenta,
|
||||||
|
bright_cyan,
|
||||||
|
bright_white
|
||||||
|
}; // enum class terminal_color
|
||||||
|
|
||||||
|
enum class emphasis : uint8_t {
|
||||||
|
bold = 1,
|
||||||
|
italic = 1 << 1,
|
||||||
|
underline = 1 << 2,
|
||||||
|
strikethrough = 1 << 3
|
||||||
|
}; // enum class emphasis
|
||||||
|
|
||||||
|
// rgb is a struct for red, green and blue colors.
|
||||||
|
// We use rgb as name because some editors will show it as color direct in the
|
||||||
|
// editor.
|
||||||
|
struct rgb {
|
||||||
|
FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {}
|
||||||
|
FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_)
|
||||||
|
: r(r_), g(g_), b(b_) {}
|
||||||
|
FMT_CONSTEXPR_DECL rgb(uint32_t hex)
|
||||||
|
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {}
|
||||||
|
FMT_CONSTEXPR_DECL rgb(color hex)
|
||||||
|
: r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF),
|
||||||
|
b(uint32_t(hex) & 0xFF) {}
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
};
|
||||||
|
|
||||||
|
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{} {
|
||||||
|
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(terminal_color term_color) FMT_NOEXCEPT
|
||||||
|
: is_rgb(), value{} {
|
||||||
|
value.term_color = static_cast<uint8_t>(term_color);
|
||||||
|
}
|
||||||
|
bool is_rgb;
|
||||||
|
union color_union {
|
||||||
|
uint8_t term_color;
|
||||||
|
uint32_t rgb_color;
|
||||||
|
} value;
|
||||||
|
};
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// Experimental text formatting support.
|
||||||
|
class text_style {
|
||||||
|
public:
|
||||||
|
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
|
||||||
|
: set_foreground_color(), set_background_color(), ems(em) {}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR text_style &operator|=(const text_style &rhs) {
|
||||||
|
if (!set_foreground_color) {
|
||||||
|
set_foreground_color = rhs.set_foreground_color;
|
||||||
|
foreground_color = rhs.foreground_color;
|
||||||
|
} else if (rhs.set_foreground_color) {
|
||||||
|
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
|
||||||
|
throw format_error("can't OR a terminal color");
|
||||||
|
foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!set_background_color) {
|
||||||
|
set_background_color = rhs.set_background_color;
|
||||||
|
background_color = rhs.background_color;
|
||||||
|
} else if (rhs.set_background_color) {
|
||||||
|
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
|
||||||
|
throw format_error("can't OR a terminal color");
|
||||||
|
background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) |
|
||||||
|
static_cast<uint8_t>(rhs.ems));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend FMT_CONSTEXPR
|
||||||
|
text_style operator|(text_style lhs, const text_style &rhs) {
|
||||||
|
return lhs |= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR text_style &operator&=(const text_style &rhs) {
|
||||||
|
if (!set_foreground_color) {
|
||||||
|
set_foreground_color = rhs.set_foreground_color;
|
||||||
|
foreground_color = rhs.foreground_color;
|
||||||
|
} else if (rhs.set_foreground_color) {
|
||||||
|
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
|
||||||
|
throw format_error("can't AND a terminal color");
|
||||||
|
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!set_background_color) {
|
||||||
|
set_background_color = rhs.set_background_color;
|
||||||
|
background_color = rhs.background_color;
|
||||||
|
} else if (rhs.set_background_color) {
|
||||||
|
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
|
||||||
|
throw format_error("can't AND a terminal color");
|
||||||
|
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
|
||||||
|
static_cast<uint8_t>(rhs.ems));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend FMT_CONSTEXPR
|
||||||
|
text_style operator&(text_style lhs, const text_style &rhs) {
|
||||||
|
return lhs &= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
|
||||||
|
return set_foreground_color;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
|
||||||
|
return set_background_color;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
|
||||||
|
return static_cast<uint8_t>(ems) != 0;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {
|
||||||
|
assert(has_foreground() && "no foreground specified for this style");
|
||||||
|
return foreground_color;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT {
|
||||||
|
assert(has_background() && "no background specified for this style");
|
||||||
|
return background_color;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
|
||||||
|
assert(has_emphasis() && "no emphasis specified for this style");
|
||||||
|
return ems;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||||
|
internal::color_type text_color) FMT_NOEXCEPT
|
||||||
|
: set_foreground_color(),
|
||||||
|
set_background_color(),
|
||||||
|
ems() {
|
||||||
|
if (is_foreground) {
|
||||||
|
foreground_color = text_color;
|
||||||
|
set_foreground_color = true;
|
||||||
|
} else {
|
||||||
|
background_color = text_color;
|
||||||
|
set_background_color = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)
|
||||||
|
FMT_NOEXCEPT;
|
||||||
|
friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background)
|
||||||
|
FMT_NOEXCEPT;
|
||||||
|
|
||||||
|
internal::color_type foreground_color;
|
||||||
|
internal::color_type background_color;
|
||||||
|
bool set_foreground_color;
|
||||||
|
bool set_background_color;
|
||||||
|
emphasis ems;
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT {
|
||||||
|
return text_style(/*is_foreground=*/true, foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT {
|
||||||
|
return text_style(/*is_foreground=*/false, background);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
|
||||||
|
return text_style(lhs) | rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
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
|
||||||
|
// sequence.
|
||||||
|
if (!text_color.is_rgb) {
|
||||||
|
bool is_background = esc == internal::data::BACKGROUND_COLOR;
|
||||||
|
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;
|
||||||
|
|
||||||
|
std::size_t index = 0;
|
||||||
|
buffer[index++] = static_cast<Char>('\x1b');
|
||||||
|
buffer[index++] = static_cast<Char>('[');
|
||||||
|
|
||||||
|
if (value >= 100u) {
|
||||||
|
buffer[index++] = static_cast<Char>('1');
|
||||||
|
value %= 100u;
|
||||||
|
}
|
||||||
|
buffer[index++] = static_cast<Char>('0' + value / 10u);
|
||||||
|
buffer[index++] = static_cast<Char>('0' + value % 10u);
|
||||||
|
|
||||||
|
buffer[index++] = static_cast<Char>('m');
|
||||||
|
buffer[index++] = static_cast<Char>('\0');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
buffer[i] = static_cast<Char>(esc[i]);
|
||||||
|
}
|
||||||
|
rgb color(text_color.value.rgb_color);
|
||||||
|
to_esc(color.r, buffer + 7, ';');
|
||||||
|
to_esc(color.g, buffer + 11, ';');
|
||||||
|
to_esc(color.b, buffer + 15, 'm');
|
||||||
|
buffer[19] = static_cast<Char>(0);
|
||||||
|
}
|
||||||
|
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::strikethrough))
|
||||||
|
em_codes[3] = 9;
|
||||||
|
|
||||||
|
std::size_t index = 0;
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
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]);
|
||||||
|
buffer[index++] = static_cast<Char>('m');
|
||||||
|
}
|
||||||
|
buffer[index++] = static_cast<Char>(0);
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR operator const Char *() const FMT_NOEXCEPT { return buffer; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Char buffer[7u + 3u * 4u + 1u];
|
||||||
|
|
||||||
|
static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out,
|
||||||
|
char delimiter) FMT_NOEXCEPT {
|
||||||
|
out[0] = static_cast<Char>('0' + c / 100);
|
||||||
|
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||||
|
out[2] = static_cast<Char>('0' + c % 10);
|
||||||
|
out[3] = static_cast<Char>(delimiter);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
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 {
|
||||||
|
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 {
|
||||||
|
return ansi_color_escape<Char>(em);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
inline void fputs(const Char *chars, FILE *stream) FMT_NOEXCEPT {
|
||||||
|
std::fputs(chars, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
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 {
|
||||||
|
fputs(internal::data::RESET_COLOR, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline void reset_color<wchar_t>(FILE *stream) FMT_NOEXCEPT {
|
||||||
|
fputs(internal::data::WRESET_COLOR, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following specialiazation disables using std::FILE as a character type,
|
||||||
|
// 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 {};
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename S, typename Char = typename internal::char_t<S>::type>
|
||||||
|
void vprint(std::FILE *f, const text_style &ts, const S &format,
|
||||||
|
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||||
|
bool has_style = false;
|
||||||
|
if (ts.has_emphasis()) {
|
||||||
|
has_style = true;
|
||||||
|
internal::fputs<Char>(
|
||||||
|
internal::make_emphasis<Char>(ts.get_emphasis()), f);
|
||||||
|
}
|
||||||
|
if (ts.has_foreground()) {
|
||||||
|
has_style = true;
|
||||||
|
internal::fputs<Char>(
|
||||||
|
internal::make_foreground_color<Char>(ts.get_foreground()), f);
|
||||||
|
}
|
||||||
|
if (ts.has_background()) {
|
||||||
|
has_style = true;
|
||||||
|
internal::fputs<Char>(
|
||||||
|
internal::make_background_color<Char>(ts.get_background()), f);
|
||||||
|
}
|
||||||
|
vprint(f, format, args);
|
||||||
|
if (has_style) {
|
||||||
|
internal::reset_color<Char>(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Formats a string and prints it to the specified file stream using ANSI
|
||||||
|
escape sequences to specify text formatting.
|
||||||
|
Example:
|
||||||
|
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||||
|
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
|
*/
|
||||||
|
template <typename String, typename... Args>
|
||||||
|
typename std::enable_if<internal::is_string<String>::value>::type print(
|
||||||
|
std::FILE *f, const text_style &ts, const String &format_str,
|
||||||
|
const Args &... args) {
|
||||||
|
internal::check_format_string<Args...>(format_str);
|
||||||
|
typedef typename internal::char_t<String>::type char_t;
|
||||||
|
typedef typename buffer_context<char_t>::type context_t;
|
||||||
|
format_arg_store<context_t, Args...> as{args...};
|
||||||
|
vprint(f, ts, format_str, basic_format_args<context_t>(as));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Formats a string and prints it to stdout using ANSI escape sequences to
|
||||||
|
specify text formatting.
|
||||||
|
Example:
|
||||||
|
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||||
|
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
return print(stdout, ts, format_str, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_COLOR_H_
|
File diff suppressed because it is too large
Load Diff
@ -136,12 +136,14 @@ int safe_strerror(
|
|||||||
ERANGE : result;
|
ERANGE : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !FMT_MSC_VER
|
||||||
// Fallback to strerror if strerror_r and strerror_s are not available.
|
// Fallback to strerror if strerror_r and strerror_s are not available.
|
||||||
int fallback(internal::null<>) {
|
int fallback(internal::null<>) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
buffer_ = strerror(error_code_);
|
buffer_ = strerror(error_code_);
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
dispatcher(int err_code, char *&buf, std::size_t buf_size)
|
dispatcher(int err_code, char *&buf, std::size_t buf_size)
|
||||||
@ -170,7 +172,7 @@ void format_error_code(internal::buffer &out, int error_code,
|
|||||||
abs_value = 0 - abs_value;
|
abs_value = 0 - abs_value;
|
||||||
++error_code_size;
|
++error_code_size;
|
||||||
}
|
}
|
||||||
error_code_size += internal::count_digits(abs_value);
|
error_code_size += internal::to_unsigned(internal::count_digits(abs_value));
|
||||||
writer w(out);
|
writer w(out);
|
||||||
if (message.size() <= inline_buffer_size - error_code_size) {
|
if (message.size() <= inline_buffer_size - error_code_size) {
|
||||||
w.write(message);
|
w.write(message);
|
||||||
@ -192,34 +194,39 @@ void report_error(FormatFunc func, int error_code,
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
|
||||||
class locale {
|
|
||||||
private:
|
|
||||||
std::locale locale_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit locale(std::locale loc = std::locale()) : locale_(loc) {}
|
|
||||||
std::locale get() { return locale_; }
|
|
||||||
};
|
|
||||||
|
|
||||||
FMT_FUNC size_t internal::count_code_points(u8string_view s) {
|
|
||||||
const char8_t *data = s.data();
|
const char8_t *data = s.data();
|
||||||
int num_code_points = 0;
|
size_t num_code_points = 0;
|
||||||
for (size_t i = 0, size = s.size(); i != size; ++i) {
|
for (size_t i = 0, size = s.size(); i != size; ++i) {
|
||||||
if ((data[i].value & 0xc0) != 0x80)
|
if ((data[i] & 0xc0) != 0x80)
|
||||||
++num_code_points;
|
++num_code_points;
|
||||||
}
|
}
|
||||||
return num_code_points;
|
return num_code_points;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
template <typename Locale>
|
||||||
|
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 {
|
||||||
|
static_assert(std::is_same<Locale, std::locale>::value, "");
|
||||||
|
return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
|
FMT_FUNC Char thousands_sep_impl(locale_ref loc) {
|
||||||
std::locale loc = lp ? lp->locale().get() : std::locale();
|
return std::use_facet<std::numpunct<Char> >(
|
||||||
return std::use_facet<std::numpunct<Char>>(loc).thousands_sep();
|
loc.get<std::locale>()).thousands_sep();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
|
FMT_FUNC Char internal::thousands_sep_impl(locale_ref) {
|
||||||
return FMT_STATIC_THOUSANDS_SEPARATOR;
|
return FMT_STATIC_THOUSANDS_SEPARATOR;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -236,19 +243,19 @@ FMT_FUNC void system_error::init(
|
|||||||
namespace internal {
|
namespace internal {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int char_traits<char>::format_float(
|
int char_traits<char>::format_float(
|
||||||
char *buffer, std::size_t size, const char *format, int precision, T value) {
|
char *buf, std::size_t size, const char *format, int precision, T value) {
|
||||||
return precision < 0 ?
|
return precision < 0 ?
|
||||||
FMT_SNPRINTF(buffer, size, format, value) :
|
FMT_SNPRINTF(buf, size, format, value) :
|
||||||
FMT_SNPRINTF(buffer, size, format, precision, value);
|
FMT_SNPRINTF(buf, size, format, precision, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int char_traits<wchar_t>::format_float(
|
int char_traits<wchar_t>::format_float(
|
||||||
wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
|
wchar_t *buf, std::size_t size, const wchar_t *format, int precision,
|
||||||
T value) {
|
T value) {
|
||||||
return precision < 0 ?
|
return precision < 0 ?
|
||||||
FMT_SWPRINTF(buffer, size, format, value) :
|
FMT_SWPRINTF(buf, size, format, value) :
|
||||||
FMT_SWPRINTF(buffer, size, format, precision, value);
|
FMT_SWPRINTF(buf, size, format, precision, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -337,6 +344,8 @@ const int16_t basic_data<T>::POW10_EXPONENTS[] = {
|
|||||||
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>::RESET_COLOR[] = "\x1b[0m";
|
template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
|
||||||
template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
|
template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
|
||||||
|
|
||||||
@ -363,7 +372,7 @@ class fp {
|
|||||||
sizeof(significand_type) * char_size;
|
sizeof(significand_type) * char_size;
|
||||||
|
|
||||||
fp(): f(0), e(0) {}
|
fp(): f(0), e(0) {}
|
||||||
fp(uint64_t f, int e): f(f), e(e) {}
|
fp(uint64_t f_val, int e_val): f(f_val), e(e_val) {}
|
||||||
|
|
||||||
// Constructs fp from an IEEE754 double. It is a template to prevent compile
|
// Constructs fp from an IEEE754 double. It is a template to prevent compile
|
||||||
// errors on platforms where double is not IEEE754.
|
// errors on platforms where double is not IEEE754.
|
||||||
@ -454,19 +463,28 @@ FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
|
|||||||
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
|
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FMT_FUNC bool grisu2_round(
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (size > max_digits) {
|
||||||
|
--size;
|
||||||
|
++exp10;
|
||||||
|
if (buf[size] >= '5')
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Generates output using Grisu2 digit-gen algorithm.
|
// Generates output using Grisu2 digit-gen algorithm.
|
||||||
FMT_FUNC void grisu2_gen_digits(
|
FMT_FUNC bool grisu2_gen_digits(
|
||||||
const fp &scaled_value, const fp &scaled_upper, uint64_t delta,
|
char *buf, int &size, uint32_t hi, uint64_t lo, int &exp,
|
||||||
char *buffer, size_t &size, int &dec_exp) {
|
uint64_t delta, const fp &one, const fp &diff, int max_digits) {
|
||||||
internal::fp one(1ull << -scaled_upper.e, scaled_upper.e);
|
// Generate digits for the most significant part (hi).
|
||||||
// hi (p1 in Grisu) contains the most significant digits of scaled_upper.
|
|
||||||
// hi = floor(scaled_upper / one).
|
|
||||||
uint32_t hi = static_cast<uint32_t>(scaled_upper.f >> -one.e);
|
|
||||||
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
|
|
||||||
// lo = scaled_upper mod 1.
|
|
||||||
uint64_t lo = scaled_upper.f & (one.f - 1);
|
|
||||||
size = 0;
|
|
||||||
auto exp = count_digits(hi); // kappa in Grisu.
|
|
||||||
while (exp > 0) {
|
while (exp > 0) {
|
||||||
uint32_t digit = 0;
|
uint32_t digit = 0;
|
||||||
// This optimization by miloyip reduces the number of integer divisions by
|
// This optimization by miloyip reduces the number of integer divisions by
|
||||||
@ -486,148 +504,32 @@ FMT_FUNC void grisu2_gen_digits(
|
|||||||
FMT_ASSERT(false, "invalid number of digits");
|
FMT_ASSERT(false, "invalid number of digits");
|
||||||
}
|
}
|
||||||
if (digit != 0 || size != 0)
|
if (digit != 0 || size != 0)
|
||||||
buffer[size++] = static_cast<char>('0' + digit);
|
buf[size++] = static_cast<char>('0' + digit);
|
||||||
--exp;
|
--exp;
|
||||||
uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
|
uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
|
||||||
if (remainder <= delta) {
|
if (remainder <= delta || size > max_digits) {
|
||||||
dec_exp += exp;
|
return grisu2_round(
|
||||||
// TODO: use scaled_value
|
buf, size, max_digits, delta, remainder,
|
||||||
(void)scaled_value;
|
static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e,
|
||||||
return;
|
diff.f, exp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Generate digits for the least significant part (lo).
|
||||||
for (;;) {
|
for (;;) {
|
||||||
lo *= 10;
|
lo *= 10;
|
||||||
delta *= 10;
|
delta *= 10;
|
||||||
char digit = static_cast<char>(lo >> -one.e);
|
char digit = static_cast<char>(lo >> -one.e);
|
||||||
if (digit != 0 || size != 0)
|
if (digit != 0 || size != 0)
|
||||||
buffer[size++] = static_cast<char>('0' + digit);
|
buf[size++] = static_cast<char>('0' + digit);
|
||||||
lo &= one.f - 1;
|
lo &= one.f - 1;
|
||||||
--exp;
|
--exp;
|
||||||
if (lo < delta) {
|
if (lo < delta || size > max_digits) {
|
||||||
dec_exp += exp;
|
return grisu2_round(buf, size, max_digits, delta, lo, one.f,
|
||||||
return;
|
diff.f * data::POWERS_OF_10_32[-exp], exp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC void grisu2_format_positive(double value, char *buffer, size_t &size,
|
|
||||||
int &dec_exp) {
|
|
||||||
FMT_ASSERT(value > 0, "value is nonpositive");
|
|
||||||
fp fp_value(value);
|
|
||||||
fp lower, upper; // w^- and w^+ in the Grisu paper.
|
|
||||||
fp_value.compute_boundaries(lower, upper);
|
|
||||||
// Find a cached power of 10 close to 1 / upper.
|
|
||||||
const int min_exp = -60; // alpha in Grisu.
|
|
||||||
auto dec_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
|
|
||||||
min_exp - (upper.e + fp::significand_size), dec_exp);
|
|
||||||
dec_exp = -dec_exp;
|
|
||||||
fp_value.normalize();
|
|
||||||
fp scaled_value = fp_value * dec_pow;
|
|
||||||
fp scaled_lower = lower * dec_pow; // \tilde{M}^- in Grisu.
|
|
||||||
fp scaled_upper = upper * dec_pow; // \tilde{M}^+ in Grisu.
|
|
||||||
++scaled_lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
|
|
||||||
--scaled_upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
|
|
||||||
uint64_t delta = scaled_upper.f - scaled_lower.f;
|
|
||||||
grisu2_gen_digits(scaled_value, scaled_upper, delta, buffer, size, dec_exp);
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_FUNC void round(char *buffer, size_t &size, int &exp,
|
|
||||||
int digits_to_remove) {
|
|
||||||
size -= to_unsigned(digits_to_remove);
|
|
||||||
exp += digits_to_remove;
|
|
||||||
int digit = buffer[size] - '0';
|
|
||||||
// TODO: proper rounding and carry
|
|
||||||
if (digit > 5 || (digit == 5 && (digits_to_remove > 1 ||
|
|
||||||
(buffer[size - 1] - '0') % 2) != 0)) {
|
|
||||||
++buffer[size - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes the exponent exp in the form "[+-]d{1,3}" to buffer.
|
|
||||||
FMT_FUNC char *write_exponent(char *buffer, int exp) {
|
|
||||||
FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
|
|
||||||
if (exp < 0) {
|
|
||||||
*buffer++ = '-';
|
|
||||||
exp = -exp;
|
|
||||||
} else {
|
|
||||||
*buffer++ = '+';
|
|
||||||
}
|
|
||||||
if (exp >= 100) {
|
|
||||||
*buffer++ = static_cast<char>('0' + exp / 100);
|
|
||||||
exp %= 100;
|
|
||||||
const char *d = data::DIGITS + exp * 2;
|
|
||||||
*buffer++ = d[0];
|
|
||||||
*buffer++ = d[1];
|
|
||||||
} else {
|
|
||||||
const char *d = data::DIGITS + exp * 2;
|
|
||||||
*buffer++ = d[0];
|
|
||||||
*buffer++ = d[1];
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_FUNC void format_exp_notation(
|
|
||||||
char *buffer, size_t &size, int exp, int precision, bool upper) {
|
|
||||||
// Insert a decimal point after the first digit and add an exponent.
|
|
||||||
std::memmove(buffer + 2, buffer + 1, size - 1);
|
|
||||||
buffer[1] = '.';
|
|
||||||
exp += static_cast<int>(size) - 1;
|
|
||||||
int num_digits = precision - static_cast<int>(size) + 1;
|
|
||||||
if (num_digits > 0) {
|
|
||||||
std::uninitialized_fill_n(buffer + size + 1, num_digits, '0');
|
|
||||||
size += to_unsigned(num_digits);
|
|
||||||
} else if (num_digits < 0) {
|
|
||||||
round(buffer, size, exp, -num_digits);
|
|
||||||
}
|
|
||||||
char *p = buffer + size + 1;
|
|
||||||
*p++ = upper ? 'E' : 'e';
|
|
||||||
size = to_unsigned(write_exponent(p, exp) - buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prettifies the output of the Grisu2 algorithm.
|
|
||||||
// The number is given as v = buffer * 10^exp.
|
|
||||||
FMT_FUNC void grisu2_prettify(char *buffer, size_t &size, int exp,
|
|
||||||
int precision, bool upper) {
|
|
||||||
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
|
|
||||||
int int_size = static_cast<int>(size);
|
|
||||||
int full_exp = int_size + exp;
|
|
||||||
const int exp_threshold = 21;
|
|
||||||
if (int_size <= full_exp && full_exp <= exp_threshold) {
|
|
||||||
// 1234e7 -> 12340000000[.0+]
|
|
||||||
std::uninitialized_fill_n(buffer + int_size, full_exp - int_size, '0');
|
|
||||||
char *p = buffer + full_exp;
|
|
||||||
if (precision > 0) {
|
|
||||||
*p++ = '.';
|
|
||||||
std::uninitialized_fill_n(p, precision, '0');
|
|
||||||
p += precision;
|
|
||||||
}
|
|
||||||
size = to_unsigned(p - buffer);
|
|
||||||
} else if (0 < full_exp && full_exp <= exp_threshold) {
|
|
||||||
// 1234e-2 -> 12.34[0+]
|
|
||||||
int fractional_size = -exp;
|
|
||||||
std::memmove(buffer + full_exp + 1, buffer + full_exp,
|
|
||||||
to_unsigned(fractional_size));
|
|
||||||
buffer[full_exp] = '.';
|
|
||||||
int num_zeros = precision - fractional_size;
|
|
||||||
if (num_zeros > 0) {
|
|
||||||
std::uninitialized_fill_n(buffer + size + 1, num_zeros, '0');
|
|
||||||
size += to_unsigned(num_zeros);
|
|
||||||
}
|
|
||||||
++size;
|
|
||||||
} else if (-6 < full_exp && full_exp <= 0) {
|
|
||||||
// 1234e-6 -> 0.001234
|
|
||||||
int offset = 2 - full_exp;
|
|
||||||
std::memmove(buffer + offset, buffer, size);
|
|
||||||
buffer[0] = '0';
|
|
||||||
buffer[1] = '.';
|
|
||||||
std::uninitialized_fill_n(buffer + 2, -full_exp, '0');
|
|
||||||
size = to_unsigned(int_size + offset);
|
|
||||||
} else {
|
|
||||||
format_exp_notation(buffer, size, exp, precision, upper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FMT_CLANG_VERSION
|
#if FMT_CLANG_VERSION
|
||||||
# define FMT_FALLTHROUGH [[clang::fallthrough]];
|
# define FMT_FALLTHROUGH [[clang::fallthrough]];
|
||||||
#elif FMT_GCC_VERSION >= 700
|
#elif FMT_GCC_VERSION >= 700
|
||||||
@ -636,58 +538,270 @@ FMT_FUNC void grisu2_prettify(char *buffer, size_t &size, int exp,
|
|||||||
# define FMT_FALLTHROUGH
|
# define FMT_FALLTHROUGH
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Formats a nonnegative value using Grisu2 algorithm. Grisu2 doesn't give any
|
struct gen_digits_params {
|
||||||
// guarantees on the shortness of the result.
|
int num_digits;
|
||||||
FMT_FUNC void grisu2_format(double value, char *buffer, size_t &size, char type,
|
bool fixed;
|
||||||
int precision, bool write_decimal_point) {
|
bool upper;
|
||||||
FMT_ASSERT(value >= 0, "value is negative");
|
bool trailing_zeros;
|
||||||
int dec_exp = 0; // K in Grisu.
|
};
|
||||||
if (value > 0) {
|
|
||||||
grisu2_format_positive(value, buffer, size, dec_exp);
|
struct prettify_handler {
|
||||||
|
char *data;
|
||||||
|
ptrdiff_t size;
|
||||||
|
buffer &buf;
|
||||||
|
|
||||||
|
explicit prettify_handler(buffer &b, ptrdiff_t n)
|
||||||
|
: data(b.data()), size(n), buf(b) {}
|
||||||
|
~prettify_handler() {
|
||||||
|
assert(buf.size() >= to_unsigned(size));
|
||||||
|
buf.resize(to_unsigned(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(ptrdiff_t pos, char c) {
|
||||||
|
std::memmove(data + pos + 1, data + pos, to_unsigned(size - pos));
|
||||||
|
data[pos] = c;
|
||||||
|
++size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(ptrdiff_t n, char c) {
|
||||||
|
std::uninitialized_fill_n(data + size, n, c);
|
||||||
|
size += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(char c) { data[size++] = c; }
|
||||||
|
|
||||||
|
void remove_trailing(char c) {
|
||||||
|
while (data[size - 1] == c) --size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
|
||||||
|
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('-');
|
||||||
|
exp = -exp;
|
||||||
} else {
|
} else {
|
||||||
*buffer = '0';
|
h.append('+');
|
||||||
size = 1;
|
|
||||||
}
|
}
|
||||||
const int default_precision = 6;
|
if (exp >= 100) {
|
||||||
if (precision < 0)
|
h.append(static_cast<char>('0' + exp / 100));
|
||||||
precision = default_precision;
|
exp %= 100;
|
||||||
bool upper = false;
|
const char *d = data::DIGITS + exp * 2;
|
||||||
switch (type) {
|
h.append(d[0]);
|
||||||
case 'G':
|
h.append(d[1]);
|
||||||
upper = true;
|
} else {
|
||||||
FMT_FALLTHROUGH
|
const char *d = data::DIGITS + exp * 2;
|
||||||
case '\0': case 'g': {
|
h.append(d[0]);
|
||||||
int digits_to_remove = static_cast<int>(size) - precision;
|
h.append(d[1]);
|
||||||
if (digits_to_remove > 0) {
|
|
||||||
round(buffer, size, dec_exp, digits_to_remove);
|
|
||||||
// Remove trailing zeros.
|
|
||||||
while (size > 0 && buffer[size - 1] == '0') {
|
|
||||||
--size;
|
|
||||||
++dec_exp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
precision = 0;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 'F':
|
}
|
||||||
upper = true;
|
|
||||||
FMT_FALLTHROUGH
|
struct fill {
|
||||||
case 'f': {
|
size_t n;
|
||||||
int digits_to_remove = -dec_exp - precision;
|
void operator()(char *buf) const {
|
||||||
if (digits_to_remove > 0) {
|
buf[0] = '0';
|
||||||
if (digits_to_remove >= static_cast<int>(size))
|
buf[1] = '.';
|
||||||
digits_to_remove = static_cast<int>(size) - 1;
|
std::uninitialized_fill_n(buf + 2, n, '0');
|
||||||
round(buffer, size, dec_exp, digits_to_remove);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 'e': case 'E':
|
};
|
||||||
format_exp_notation(buffer, size, dec_exp, precision, type == 'E');
|
|
||||||
|
// 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) {
|
||||||
|
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');
|
||||||
|
handler.append(params.upper ? 'E' : 'e');
|
||||||
|
write_exponent(exp, handler);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (write_decimal_point && precision < 1)
|
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
|
||||||
precision = 1;
|
int full_exp = size + exp;
|
||||||
grisu2_prettify(buffer, size, dec_exp, precision, upper);
|
const int exp_threshold = 21;
|
||||||
|
if (size <= full_exp && full_exp <= exp_threshold) {
|
||||||
|
// 1234e7 -> 12340000000[.0+]
|
||||||
|
handler.append(full_exp - size, '0');
|
||||||
|
int num_zeros = params.num_digits - full_exp;
|
||||||
|
if (num_zeros > 0 && params.trailing_zeros) {
|
||||||
|
handler.append('.');
|
||||||
|
handler.append(num_zeros, '0');
|
||||||
|
}
|
||||||
|
} else if (full_exp > 0) {
|
||||||
|
// 1234e-2 -> 12.34[0+]
|
||||||
|
handler.insert(full_exp, '.');
|
||||||
|
if (!params.trailing_zeros) {
|
||||||
|
// Remove trailing zeros.
|
||||||
|
handler.remove_trailing('0');
|
||||||
|
} else if (params.num_digits > size) {
|
||||||
|
// Add trailing zeros.
|
||||||
|
ptrdiff_t num_zeros = params.num_digits - size;
|
||||||
|
handler.append(num_zeros, '0');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 1234e-6 -> 0.001234
|
||||||
|
handler.insert(0, 2 - full_exp, fill{to_unsigned(-full_exp)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct char_counter {
|
||||||
|
ptrdiff_t size;
|
||||||
|
|
||||||
|
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; }
|
||||||
|
void remove_trailing(char) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Converts format specifiers into parameters for digit generation and computes
|
||||||
|
// output buffer size for a number in the range [pow(10, exp - 1), pow(10, exp)
|
||||||
|
// or 0 if exp == 1.
|
||||||
|
FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,
|
||||||
|
int exp, buffer &buf) {
|
||||||
|
auto params = gen_digits_params();
|
||||||
|
int num_digits = specs.precision >= 0 ? specs.precision : 6;
|
||||||
|
switch (specs.type) {
|
||||||
|
case 'G':
|
||||||
|
params.upper = true;
|
||||||
|
FMT_FALLTHROUGH
|
||||||
|
case '\0': case 'g':
|
||||||
|
params.trailing_zeros = (specs.flags & HASH_FLAG) != 0;
|
||||||
|
if (-4 <= exp && exp < num_digits + 1) {
|
||||||
|
params.fixed = true;
|
||||||
|
if (!specs.type && params.trailing_zeros && exp >= 0)
|
||||||
|
num_digits = exp + 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
params.upper = true;
|
||||||
|
FMT_FALLTHROUGH
|
||||||
|
case 'f': {
|
||||||
|
params.fixed = true;
|
||||||
|
params.trailing_zeros = true;
|
||||||
|
int adjusted_min_digits = num_digits + exp;
|
||||||
|
if (adjusted_min_digits > 0)
|
||||||
|
num_digits = adjusted_min_digits;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'E':
|
||||||
|
params.upper = true;
|
||||||
|
FMT_FALLTHROUGH
|
||||||
|
case 'e':
|
||||||
|
++num_digits;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
params.num_digits = num_digits;
|
||||||
|
char_counter counter{num_digits};
|
||||||
|
grisu2_prettify(params, params.num_digits, exp - num_digits, counter);
|
||||||
|
buf.resize(to_unsigned(counter.size));
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Double>
|
||||||
|
FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
|
||||||
|
grisu2_format(Double value, buffer &buf, core_format_specs specs) {
|
||||||
|
FMT_ASSERT(value >= 0, "value is negative");
|
||||||
|
if (value == 0) {
|
||||||
|
gen_digits_params params = process_specs(specs, 1, buf);
|
||||||
|
const size_t size = 1;
|
||||||
|
buf[0] = '0';
|
||||||
|
grisu2_prettify(params, size, 0, prettify_handler(buf, size));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp fp_value(value);
|
||||||
|
fp lower, upper; // w^- and w^+ in the Grisu paper.
|
||||||
|
fp_value.compute_boundaries(lower, upper);
|
||||||
|
|
||||||
|
// Find a cached power of 10 close to 1 / upper and use it to scale upper.
|
||||||
|
const int min_exp = -60; // alpha in Grisu.
|
||||||
|
int cached_exp = 0; // K in Grisu.
|
||||||
|
auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
|
||||||
|
min_exp - (upper.e + fp::significand_size), cached_exp);
|
||||||
|
cached_exp = -cached_exp;
|
||||||
|
upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
|
||||||
|
--upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
|
||||||
|
fp one(1ull << -upper.e, upper.e);
|
||||||
|
// hi (p1 in Grisu) contains the most significant digits of scaled_upper.
|
||||||
|
// hi = floor(upper / one).
|
||||||
|
uint32_t hi = static_cast<uint32_t>(upper.f >> -one.e);
|
||||||
|
int exp = count_digits(hi); // kappa in Grisu.
|
||||||
|
gen_digits_params params = process_specs(specs, cached_exp + exp, buf);
|
||||||
|
fp_value.normalize();
|
||||||
|
fp scaled_value = fp_value * cached_pow;
|
||||||
|
lower = lower * cached_pow; // \tilde{M}^- in Grisu.
|
||||||
|
++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
|
||||||
|
uint64_t delta = upper.f - lower.f;
|
||||||
|
fp diff = upper - scaled_value; // wp_w in Grisu.
|
||||||
|
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
|
||||||
|
// lo = supper % one.
|
||||||
|
uint64_t lo = upper.f & (one.f - 1);
|
||||||
|
int size = 0;
|
||||||
|
if (!grisu2_gen_digits(buf.data(), size, hi, lo, exp, delta, one, diff,
|
||||||
|
params.num_digits)) {
|
||||||
|
buf.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
grisu2_prettify(params, size, cached_exp + exp, prettify_handler(buf, size));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Double>
|
||||||
|
void sprintf_format(Double value, internal::buffer &buf,
|
||||||
|
core_format_specs spec) {
|
||||||
|
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
|
||||||
|
FMT_ASSERT(buf.capacity() != 0, "empty buffer");
|
||||||
|
|
||||||
|
// Build format string.
|
||||||
|
enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
|
||||||
|
char format[MAX_FORMAT_SIZE];
|
||||||
|
char *format_ptr = format;
|
||||||
|
*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';
|
||||||
|
*format_ptr++ = spec.type;
|
||||||
|
*format_ptr = '\0';
|
||||||
|
|
||||||
|
// Format using snprintf.
|
||||||
|
char *start = FMT_NULL;
|
||||||
|
for (;;) {
|
||||||
|
std::size_t buffer_size = buf.capacity();
|
||||||
|
start = &buf[0];
|
||||||
|
int result = internal::char_traits<char>::format_float(
|
||||||
|
start, buffer_size, format, spec.precision, value);
|
||||||
|
if (result >= 0) {
|
||||||
|
unsigned n = internal::to_unsigned(result);
|
||||||
|
if (n < buf.capacity()) {
|
||||||
|
buf.resize(n);
|
||||||
|
break; // The buffer is large enough - continue with formatting.
|
||||||
|
}
|
||||||
|
buf.reserve(n + 1);
|
||||||
|
} else {
|
||||||
|
// If result is negative we ask to increase the capacity by at least 1,
|
||||||
|
// but as std::vector, the buffer grows exponentially.
|
||||||
|
buf.reserve(buf.capacity() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
@ -812,11 +926,6 @@ FMT_FUNC void format_system_error(
|
|||||||
format_error_code(out, error_code, message);
|
format_error_code(out, error_code, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
void basic_fixed_buffer<Char>::grow(std::size_t) {
|
|
||||||
FMT_THROW(std::runtime_error("buffer overflow"));
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_FUNC void internal::error_handler::on_error(const char *message) {
|
FMT_FUNC void internal::error_handler::on_error(const char *message) {
|
||||||
FMT_THROW(format_error(message));
|
FMT_THROW(format_error(message));
|
||||||
}
|
}
|
||||||
@ -835,13 +944,14 @@ FMT_FUNC void report_windows_error(
|
|||||||
|
|
||||||
FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
|
FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
vformat_to(buffer, format_str, args);
|
internal::vformat_to(buffer, format_str,
|
||||||
|
basic_format_args<buffer_context<char>::type>(args));
|
||||||
std::fwrite(buffer.data(), 1, buffer.size(), f);
|
std::fwrite(buffer.data(), 1, buffer.size(), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
|
FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
|
||||||
wmemory_buffer buffer;
|
wmemory_buffer buffer;
|
||||||
vformat_to(buffer, format_str, args);
|
internal::vformat_to(buffer, format_str, args);
|
||||||
std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
|
std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -853,10 +963,6 @@ FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
|
|||||||
vprint(stdout, format_str, args);
|
vprint(stdout, format_str, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
|
||||||
FMT_FUNC locale locale_provider::locale() { return fmt::locale(); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
File diff suppressed because it is too large
Load Diff
77
include/spdlog/fmt/bundled/locale.h
Normal file
77
include/spdlog/fmt/bundled/locale.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Formatting library for C++ - std::locale support
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_LOCALE_H_
|
||||||
|
#define FMT_LOCALE_H_
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
template <typename Char>
|
||||||
|
typename buffer_context<Char>::type::iterator vformat_to(
|
||||||
|
const std::locale &loc, basic_buffer<Char> &buf,
|
||||||
|
basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||||
|
typedef back_insert_range<basic_buffer<Char> > range;
|
||||||
|
return vformat_to<arg_formatter<range>>(
|
||||||
|
buf, to_string_view(format_str), args, internal::locale_ref(loc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
std::basic_string<Char> vformat(
|
||||||
|
const std::locale &loc, basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
internal::vformat_to(loc, buffer, format_str, args);
|
||||||
|
return fmt::to_string(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename Char = FMT_CHAR(S)>
|
||||||
|
inline std::basic_string<Char> vformat(
|
||||||
|
const std::locale &loc, const S &format_str,
|
||||||
|
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||||
|
return internal::vformat(loc, to_string_view(format_str), args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename... Args>
|
||||||
|
inline std::basic_string<FMT_CHAR(S)> format(
|
||||||
|
const std::locale &loc, const S &format_str, const Args &... args) {
|
||||||
|
return internal::vformat(
|
||||||
|
loc, to_string_view(format_str),
|
||||||
|
*internal::checked_args<S, Args...>(format_str, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename String, typename OutputIt, typename... Args>
|
||||||
|
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
|
||||||
|
OutputIt>::type
|
||||||
|
vformat_to(OutputIt out, const std::locale &loc, const String &format_str,
|
||||||
|
typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
|
||||||
|
typedef output_range<OutputIt, FMT_CHAR(String)> range;
|
||||||
|
return vformat_to<arg_formatter<range>>(
|
||||||
|
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename S, typename... Args>
|
||||||
|
inline typename std::enable_if<
|
||||||
|
internal::is_string<S>::value &&
|
||||||
|
internal::is_output_iterator<OutputIt>::value, OutputIt>::type
|
||||||
|
format_to(OutputIt out, const std::locale &loc, const S &format_str,
|
||||||
|
const Args &... args) {
|
||||||
|
internal::check_format_string<Args...>(format_str);
|
||||||
|
typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;
|
||||||
|
format_arg_store<context, Args...> as{args...};
|
||||||
|
return vformat_to(out, loc, to_string_view(format_str),
|
||||||
|
basic_format_args<context>(as));
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_LOCALE_H_
|
@ -1,6 +1,6 @@
|
|||||||
// Formatting library for C++ - std::ostream support
|
// Formatting library for C++ - std::ostream support
|
||||||
//
|
//
|
||||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// For the license information refer to format.h.
|
// For the license information refer to format.h.
|
||||||
@ -129,7 +129,7 @@ inline void vprint(std::basic_ostream<Char> &os,
|
|||||||
basic_string_view<Char> format_str,
|
basic_string_view<Char> format_str,
|
||||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
vformat_to(buffer, format_str, args);
|
internal::vformat_to(buffer, format_str, args);
|
||||||
internal::write(os, buffer);
|
internal::write(os, buffer);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -141,16 +141,12 @@ inline void vprint(std::basic_ostream<Char> &os,
|
|||||||
fmt::print(cerr, "Don't {}!", "panic");
|
fmt::print(cerr, "Don't {}!", "panic");
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename S, typename... Args>
|
||||||
inline void print(std::ostream &os, string_view format_str,
|
inline typename std::enable_if<internal::is_string<S>::value>::type
|
||||||
const Args & ... args) {
|
print(std::basic_ostream<FMT_CHAR(S)> &os, const S &format_str,
|
||||||
vprint<char>(os, format_str, make_format_args<format_context>(args...));
|
const Args & ... args) {
|
||||||
}
|
internal::checked_args<S, Args...> ca(format_str, args...);
|
||||||
|
vprint(os, to_string_view(format_str), *ca);
|
||||||
template <typename... Args>
|
|
||||||
inline void print(std::wostream &os, wstring_view format_str,
|
|
||||||
const Args & ... args) {
|
|
||||||
vprint<wchar_t>(os, format_str, make_format_args<wformat_context>(args...));
|
|
||||||
}
|
}
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ class buffered_file {
|
|||||||
buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
|
buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
|
||||||
|
|
||||||
// Destroys the object closing the file it represents if any.
|
// Destroys the object closing the file it represents if any.
|
||||||
FMT_API ~buffered_file() FMT_DTOR_NOEXCEPT;
|
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
buffered_file(const buffered_file &) = delete;
|
buffered_file(const buffered_file &) = delete;
|
||||||
@ -223,7 +223,7 @@ class file {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Destroys the object closing the file it represents if any.
|
// Destroys the object closing the file it represents if any.
|
||||||
FMT_API ~file() FMT_DTOR_NOEXCEPT;
|
FMT_API ~file() FMT_NOEXCEPT;
|
||||||
|
|
||||||
// Returns the file descriptor.
|
// Returns the file descriptor.
|
||||||
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
||||||
|
@ -16,6 +16,130 @@
|
|||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
// An iterator that produces a null terminator on *end. This simplifies parsing
|
||||||
|
// and allows comparing the performance of processing a null-terminated string
|
||||||
|
// vs string_view.
|
||||||
|
template <typename Char>
|
||||||
|
class null_terminating_iterator {
|
||||||
|
public:
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef Char value_type;
|
||||||
|
typedef const Char* pointer;
|
||||||
|
typedef const Char& reference;
|
||||||
|
typedef std::random_access_iterator_tag iterator_category;
|
||||||
|
|
||||||
|
null_terminating_iterator() : ptr_(0), end_(0) {}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator(const Char *ptr, const Char *end)
|
||||||
|
: ptr_(ptr), end_(end) {}
|
||||||
|
|
||||||
|
template <typename Range>
|
||||||
|
FMT_CONSTEXPR explicit null_terminating_iterator(const Range &r)
|
||||||
|
: ptr_(r.begin()), end_(r.end()) {}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator &operator=(const Char *ptr) {
|
||||||
|
assert(ptr <= end_);
|
||||||
|
ptr_ = ptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR Char operator*() const {
|
||||||
|
return ptr_ != end_ ? *ptr_ : Char();
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator operator++() {
|
||||||
|
++ptr_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator operator++(int) {
|
||||||
|
null_terminating_iterator result(*this);
|
||||||
|
++ptr_;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator operator--() {
|
||||||
|
--ptr_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator operator+(difference_type n) {
|
||||||
|
return null_terminating_iterator(ptr_ + n, end_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator operator-(difference_type n) {
|
||||||
|
return null_terminating_iterator(ptr_ - n, end_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator operator+=(difference_type n) {
|
||||||
|
ptr_ += n;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR difference_type operator-(
|
||||||
|
null_terminating_iterator other) const {
|
||||||
|
return ptr_ - other.ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR bool operator!=(null_terminating_iterator other) const {
|
||||||
|
return ptr_ != other.ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>=(null_terminating_iterator other) const {
|
||||||
|
return ptr_ >= other.ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should be a friend specialization pointer_from<Char> but the latter
|
||||||
|
// doesn't compile by gcc 5.1 due to a compiler bug.
|
||||||
|
template <typename CharT>
|
||||||
|
friend FMT_CONSTEXPR_DECL const CharT *pointer_from(
|
||||||
|
null_terminating_iterator<CharT> it);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Char *ptr_;
|
||||||
|
const Char *end_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FMT_CONSTEXPR const T *pointer_from(const T *p) { return p; }
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator<Char> it) {
|
||||||
|
return it.ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: Parses the input as an unsigned integer. This function assumes
|
||||||
|
// that the first character is a digit and presence of a non-digit character at
|
||||||
|
// the end.
|
||||||
|
// it: an iterator pointing to the beginning of the input range.
|
||||||
|
template <typename Iterator, typename ErrorHandler>
|
||||||
|
FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) {
|
||||||
|
assert('0' <= *it && *it <= '9');
|
||||||
|
if (*it == '0') {
|
||||||
|
++it;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
unsigned value = 0;
|
||||||
|
// Convert to unsigned to prevent a warning.
|
||||||
|
unsigned max_int = (std::numeric_limits<int>::max)();
|
||||||
|
unsigned big = max_int / 10;
|
||||||
|
do {
|
||||||
|
// Check for overflow.
|
||||||
|
if (value > big) {
|
||||||
|
value = max_int + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value = value * 10 + unsigned(*it - '0');
|
||||||
|
// Workaround for MSVC "setup_exception stack overflow" error:
|
||||||
|
auto next = it;
|
||||||
|
++next;
|
||||||
|
it = next;
|
||||||
|
} while ('0' <= *it && *it <= '9');
|
||||||
|
if (value > max_int)
|
||||||
|
eh.on_error("number is too big");
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||||
// signed and unsigned integers.
|
// signed and unsigned integers.
|
||||||
template <bool IsSigned>
|
template <bool IsSigned>
|
||||||
@ -133,7 +257,7 @@ class arg_converter: public function<void> {
|
|||||||
// unsigned).
|
// unsigned).
|
||||||
template <typename T, typename Context, typename Char>
|
template <typename T, typename Context, typename Char>
|
||||||
void convert_arg(basic_format_arg<Context> &arg, Char type) {
|
void convert_arg(basic_format_arg<Context> &arg, Char type) {
|
||||||
fmt::visit(arg_converter<T, Context>(arg, type), arg);
|
visit_format_arg(arg_converter<T, Context>(arg, type), arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts an integer argument to char for printf.
|
// Converts an integer argument to char for printf.
|
||||||
@ -192,8 +316,16 @@ class printf_width_handler: public function<unsigned> {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename Context>
|
||||||
|
void printf(basic_buffer<Char> &buf, basic_string_view<Char> format,
|
||||||
|
basic_format_args<Context> args) {
|
||||||
|
Context(std::back_inserter(buf), format, args).format();
|
||||||
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
|
using internal::printf; // For printing into memory_buffer.
|
||||||
|
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
class printf_arg_formatter;
|
class printf_arg_formatter;
|
||||||
|
|
||||||
@ -222,12 +354,12 @@ class printf_arg_formatter:
|
|||||||
context_type &context_;
|
context_type &context_;
|
||||||
|
|
||||||
void write_null_pointer(char) {
|
void write_null_pointer(char) {
|
||||||
this->spec()->type_ = 0;
|
this->spec()->type = 0;
|
||||||
this->write("(nil)");
|
this->write("(nil)");
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_null_pointer(wchar_t) {
|
void write_null_pointer(wchar_t) {
|
||||||
this->spec()->type_ = 0;
|
this->spec()->type = 0;
|
||||||
this->write(L"(nil)");
|
this->write(L"(nil)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +375,8 @@ class printf_arg_formatter:
|
|||||||
*/
|
*/
|
||||||
printf_arg_formatter(internal::basic_buffer<char_type> &buffer,
|
printf_arg_formatter(internal::basic_buffer<char_type> &buffer,
|
||||||
format_specs &spec, context_type &ctx)
|
format_specs &spec, context_type &ctx)
|
||||||
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec),
|
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec,
|
||||||
|
ctx.locale()),
|
||||||
context_(ctx) {}
|
context_(ctx) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -253,15 +386,15 @@ class printf_arg_formatter:
|
|||||||
// use std::is_same instead.
|
// use std::is_same instead.
|
||||||
if (std::is_same<T, bool>::value) {
|
if (std::is_same<T, bool>::value) {
|
||||||
format_specs &fmt_spec = *this->spec();
|
format_specs &fmt_spec = *this->spec();
|
||||||
if (fmt_spec.type_ != 's')
|
if (fmt_spec.type != 's')
|
||||||
return base::operator()(value ? 1 : 0);
|
return base::operator()(value ? 1 : 0);
|
||||||
fmt_spec.type_ = 0;
|
fmt_spec.type = 0;
|
||||||
this->write(value != 0);
|
this->write(value != 0);
|
||||||
} else if (std::is_same<T, char_type>::value) {
|
} else if (std::is_same<T, char_type>::value) {
|
||||||
format_specs &fmt_spec = *this->spec();
|
format_specs &fmt_spec = *this->spec();
|
||||||
if (fmt_spec.type_ && fmt_spec.type_ != 'c')
|
if (fmt_spec.type && fmt_spec.type != 'c')
|
||||||
return (*this)(static_cast<int>(value));
|
return (*this)(static_cast<int>(value));
|
||||||
fmt_spec.flags_ = 0;
|
fmt_spec.flags = 0;
|
||||||
fmt_spec.align_ = ALIGN_RIGHT;
|
fmt_spec.align_ = ALIGN_RIGHT;
|
||||||
return base::operator()(value);
|
return base::operator()(value);
|
||||||
} else {
|
} else {
|
||||||
@ -280,7 +413,7 @@ class printf_arg_formatter:
|
|||||||
iterator operator()(const char *value) {
|
iterator operator()(const char *value) {
|
||||||
if (value)
|
if (value)
|
||||||
base::operator()(value);
|
base::operator()(value);
|
||||||
else if (this->spec()->type_ == 'p')
|
else if (this->spec()->type == 'p')
|
||||||
write_null_pointer(char_type());
|
write_null_pointer(char_type());
|
||||||
else
|
else
|
||||||
this->write("(null)");
|
this->write("(null)");
|
||||||
@ -291,7 +424,7 @@ class printf_arg_formatter:
|
|||||||
iterator operator()(const wchar_t *value) {
|
iterator operator()(const wchar_t *value) {
|
||||||
if (value)
|
if (value)
|
||||||
base::operator()(value);
|
base::operator()(value);
|
||||||
else if (this->spec()->type_ == 'p')
|
else if (this->spec()->type == 'p')
|
||||||
write_null_pointer(char_type());
|
write_null_pointer(char_type());
|
||||||
else
|
else
|
||||||
this->write(L"(null)");
|
this->write(L"(null)");
|
||||||
@ -310,7 +443,7 @@ class printf_arg_formatter:
|
|||||||
iterator operator()(const void *value) {
|
iterator operator()(const void *value) {
|
||||||
if (value)
|
if (value)
|
||||||
return base::operator()(value);
|
return base::operator()(value);
|
||||||
this->spec()->type_ = 0;
|
this->spec()->type = 0;
|
||||||
write_null_pointer(char_type());
|
write_null_pointer(char_type());
|
||||||
return this->out();
|
return this->out();
|
||||||
}
|
}
|
||||||
@ -394,16 +527,16 @@ void basic_printf_context<OutputIt, Char, AF>::parse_flags(
|
|||||||
spec.align_ = ALIGN_LEFT;
|
spec.align_ = ALIGN_LEFT;
|
||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
|
spec.flags |= SIGN_FLAG | PLUS_FLAG;
|
||||||
break;
|
break;
|
||||||
case '0':
|
case '0':
|
||||||
spec.fill_ = '0';
|
spec.fill_ = '0';
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
spec.flags_ |= SIGN_FLAG;
|
spec.flags |= SIGN_FLAG;
|
||||||
break;
|
break;
|
||||||
case '#':
|
case '#':
|
||||||
spec.flags_ |= HASH_FLAG;
|
spec.flags |= HASH_FLAG;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
--it;
|
--it;
|
||||||
@ -453,8 +586,8 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
|
|||||||
spec.width_ = parse_nonnegative_int(it, eh);
|
spec.width_ = parse_nonnegative_int(it, eh);
|
||||||
} else if (*it == '*') {
|
} else if (*it == '*') {
|
||||||
++it;
|
++it;
|
||||||
spec.width_ =
|
spec.width_ = visit_format_arg(
|
||||||
fmt::visit(internal::printf_width_handler<char_type>(spec), get_arg(it));
|
internal::printf_width_handler<char_type>(spec), get_arg(it));
|
||||||
}
|
}
|
||||||
return arg_index;
|
return arg_index;
|
||||||
}
|
}
|
||||||
@ -486,19 +619,19 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
|
|||||||
++it;
|
++it;
|
||||||
if ('0' <= *it && *it <= '9') {
|
if ('0' <= *it && *it <= '9') {
|
||||||
internal::error_handler eh;
|
internal::error_handler eh;
|
||||||
spec.precision_ = static_cast<int>(parse_nonnegative_int(it, eh));
|
spec.precision = static_cast<int>(parse_nonnegative_int(it, eh));
|
||||||
} else if (*it == '*') {
|
} else if (*it == '*') {
|
||||||
++it;
|
++it;
|
||||||
spec.precision_ =
|
spec.precision =
|
||||||
fmt::visit(internal::printf_precision_handler(), get_arg(it));
|
visit_format_arg(internal::printf_precision_handler(), get_arg(it));
|
||||||
} else {
|
} else {
|
||||||
spec.precision_ = 0;
|
spec.precision = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
format_arg arg = get_arg(it, arg_index);
|
format_arg arg = get_arg(it, arg_index);
|
||||||
if (spec.flag(HASH_FLAG) && fmt::visit(internal::is_zero_int(), arg))
|
if (spec.has(HASH_FLAG) && visit_format_arg(internal::is_zero_int(), arg))
|
||||||
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
|
spec.flags = static_cast<uint_least8_t>(spec.flags & (~internal::to_unsigned<int>(HASH_FLAG)));
|
||||||
if (spec.fill_ == '0') {
|
if (spec.fill_ == '0') {
|
||||||
if (arg.is_arithmetic())
|
if (arg.is_arithmetic())
|
||||||
spec.align_ = ALIGN_NUMERIC;
|
spec.align_ = ALIGN_NUMERIC;
|
||||||
@ -542,16 +675,17 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
|
|||||||
// Parse type.
|
// Parse type.
|
||||||
if (!*it)
|
if (!*it)
|
||||||
FMT_THROW(format_error("invalid format string"));
|
FMT_THROW(format_error("invalid format string"));
|
||||||
spec.type_ = static_cast<char>(*it++);
|
spec.type = static_cast<char>(*it++);
|
||||||
if (arg.is_integral()) {
|
if (arg.is_integral()) {
|
||||||
// Normalize type.
|
// Normalize type.
|
||||||
switch (spec.type_) {
|
switch (spec.type) {
|
||||||
case 'i': case 'u':
|
case 'i': case 'u':
|
||||||
spec.type_ = 'd';
|
spec.type = 'd';
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
// TODO: handle wchar_t better?
|
// TODO: handle wchar_t better?
|
||||||
fmt::visit(internal::char_converter<basic_printf_context>(arg), arg);
|
visit_format_arg(
|
||||||
|
internal::char_converter<basic_printf_context>(arg), arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -559,35 +693,50 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
|
|||||||
start = it;
|
start = it;
|
||||||
|
|
||||||
// Format argument.
|
// Format argument.
|
||||||
fmt::visit(AF(buffer, spec, *this), arg);
|
visit_format_arg(AF(buffer, spec, *this), arg);
|
||||||
}
|
}
|
||||||
buffer.append(pointer_from(start), pointer_from(it));
|
buffer.append(pointer_from(start), pointer_from(it));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename Context>
|
|
||||||
void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format,
|
|
||||||
basic_format_args<Context> args) {
|
|
||||||
Context(std::back_inserter(buf), format, args).format();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Buffer>
|
template <typename Buffer>
|
||||||
struct printf_context {
|
struct basic_printf_context_t {
|
||||||
typedef basic_printf_context<
|
typedef basic_printf_context<
|
||||||
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
|
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ...Args>
|
typedef basic_printf_context_t<internal::buffer>::type printf_context;
|
||||||
inline format_arg_store<printf_context<internal::buffer>::type, Args...>
|
typedef basic_printf_context_t<internal::wbuffer>::type wprintf_context;
|
||||||
make_printf_args(const Args & ... args) {
|
|
||||||
return format_arg_store<printf_context<internal::buffer>::type, Args...>(
|
|
||||||
args...);
|
|
||||||
}
|
|
||||||
typedef basic_format_args<printf_context<internal::buffer>::type> printf_args;
|
|
||||||
typedef basic_format_args<printf_context<internal::wbuffer>::type> wprintf_args;
|
|
||||||
|
|
||||||
inline std::string vsprintf(string_view format, printf_args args) {
|
typedef basic_format_args<printf_context> printf_args;
|
||||||
memory_buffer buffer;
|
typedef basic_format_args<wprintf_context> wprintf_args;
|
||||||
printf(buffer, format, args);
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Constructs an `~fmt::format_arg_store` object that contains references to
|
||||||
|
arguments and can be implicitly converted to `~fmt::printf_args`.
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template<typename... Args>
|
||||||
|
inline format_arg_store<printf_context, Args...>
|
||||||
|
make_printf_args(const Args &... args) { return {args...}; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Constructs an `~fmt::format_arg_store` object that contains references to
|
||||||
|
arguments and can be implicitly converted to `~fmt::wprintf_args`.
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template<typename... 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) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
printf(buffer, to_string_view(format), args);
|
||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,30 +749,24 @@ inline std::string vsprintf(string_view format, printf_args args) {
|
|||||||
std::string message = fmt::sprintf("The answer is %d", 42);
|
std::string message = fmt::sprintf("The answer is %d", 42);
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename S, typename... Args>
|
||||||
inline std::string sprintf(string_view format_str, const Args & ... args) {
|
inline FMT_ENABLE_IF_T(
|
||||||
return vsprintf(format_str,
|
internal::is_string<S>::value, std::basic_string<FMT_CHAR(S)>)
|
||||||
make_format_args<typename printf_context<internal::buffer>::type>(args...));
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::wstring vsprintf(wstring_view format, wprintf_args args) {
|
template <typename S, typename Char = FMT_CHAR(S)>
|
||||||
wmemory_buffer buffer;
|
inline int vfprintf(std::FILE *f, const S &format,
|
||||||
printf(buffer, format, args);
|
basic_format_args<typename basic_printf_context_t<
|
||||||
return to_string(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... Args>
|
|
||||||
inline std::wstring sprintf(wstring_view format_str, const Args & ... args) {
|
|
||||||
return vsprintf(format_str,
|
|
||||||
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
inline int vfprintf(std::FILE *f, basic_string_view<Char> format,
|
|
||||||
basic_format_args<typename printf_context<
|
|
||||||
internal::basic_buffer<Char>>::type> args) {
|
internal::basic_buffer<Char>>::type> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
printf(buffer, format, args);
|
printf(buffer, to_string_view(format), args);
|
||||||
std::size_t size = buffer.size();
|
std::size_t size = buffer.size();
|
||||||
return std::fwrite(
|
return std::fwrite(
|
||||||
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);
|
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);
|
||||||
@ -638,26 +781,22 @@ inline int vfprintf(std::FILE *f, basic_string_view<Char> format,
|
|||||||
fmt::fprintf(stderr, "Don't %s!", "panic");
|
fmt::fprintf(stderr, "Don't %s!", "panic");
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename S, typename... Args>
|
||||||
inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) {
|
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
|
||||||
auto vargs = make_format_args<
|
fprintf(std::FILE *f, const S &format, const Args & ... args) {
|
||||||
typename printf_context<internal::buffer>::type>(args...);
|
internal::check_format_string<Args...>(format);
|
||||||
return vfprintf<char>(f, format_str, vargs);
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename S, typename Char = FMT_CHAR(S)>
|
||||||
inline int fprintf(std::FILE *f, wstring_view format_str,
|
inline int vprintf(const S &format,
|
||||||
const Args & ... args) {
|
basic_format_args<typename basic_printf_context_t<
|
||||||
return vfprintf(f, format_str,
|
internal::basic_buffer<Char>>::type> args) {
|
||||||
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
|
return vfprintf(stdout, to_string_view(format), args);
|
||||||
}
|
|
||||||
|
|
||||||
inline int vprintf(string_view format, printf_args args) {
|
|
||||||
return vfprintf(stdout, format, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int vprintf(wstring_view format, wprintf_args args) {
|
|
||||||
return vfprintf(stdout, format, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -669,30 +808,24 @@ inline int vprintf(wstring_view format, wprintf_args args) {
|
|||||||
fmt::printf("Elapsed time: %.2f seconds", 1.23);
|
fmt::printf("Elapsed time: %.2f seconds", 1.23);
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename S, typename... Args>
|
||||||
inline int printf(string_view format_str, const Args & ... args) {
|
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
|
||||||
return vprintf(format_str,
|
printf(const S &format_str, const Args & ... args) {
|
||||||
make_format_args<typename printf_context<internal::buffer>::type>(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;
|
||||||
|
format_arg_store<context, Args...> as{ args... };
|
||||||
|
return vprintf(to_string_view(format_str),
|
||||||
|
basic_format_args<context>(as));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename S, typename Char = FMT_CHAR(S)>
|
||||||
inline int printf(wstring_view format_str, const Args & ... args) {
|
inline int vfprintf(std::basic_ostream<Char> &os,
|
||||||
return vprintf(format_str,
|
const S &format,
|
||||||
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
|
basic_format_args<typename basic_printf_context_t<
|
||||||
}
|
internal::basic_buffer<Char>>::type> args) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
inline int vfprintf(std::ostream &os, string_view format_str,
|
printf(buffer, to_string_view(format), args);
|
||||||
printf_args args) {
|
|
||||||
memory_buffer buffer;
|
|
||||||
printf(buffer, format_str, args);
|
|
||||||
internal::write(os, buffer);
|
|
||||||
return static_cast<int>(buffer.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int vfprintf(std::wostream &os, wstring_view format_str,
|
|
||||||
wprintf_args args) {
|
|
||||||
wmemory_buffer buffer;
|
|
||||||
printf(buffer, format_str, args);
|
|
||||||
internal::write(os, buffer);
|
internal::write(os, buffer);
|
||||||
return static_cast<int>(buffer.size());
|
return static_cast<int>(buffer.size());
|
||||||
}
|
}
|
||||||
@ -706,20 +839,16 @@ inline int vfprintf(std::wostream &os, wstring_view format_str,
|
|||||||
fmt::fprintf(cerr, "Don't %s!", "panic");
|
fmt::fprintf(cerr, "Don't %s!", "panic");
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename S, typename... Args>
|
||||||
inline int fprintf(std::ostream &os, string_view format_str,
|
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
|
||||||
const Args & ... args) {
|
fprintf(std::basic_ostream<FMT_CHAR(S)> &os,
|
||||||
auto vargs = make_format_args<
|
const S &format_str, const Args & ... args) {
|
||||||
typename printf_context<internal::buffer>::type>(args...);
|
internal::check_format_string<Args...>(format_str);
|
||||||
return vfprintf(os, format_str, vargs);
|
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
|
||||||
}
|
typedef typename basic_printf_context_t<buffer>::type context;
|
||||||
|
format_arg_store<context, Args...> as{ args... };
|
||||||
template <typename... Args>
|
return vfprintf(os, to_string_view(format_str),
|
||||||
inline int fprintf(std::wostream &os, wstring_view format_str,
|
basic_format_args<context>(as));
|
||||||
const Args & ... args) {
|
|
||||||
auto vargs = make_format_args<
|
|
||||||
typename printf_context<internal::buffer>::type>(args...);
|
|
||||||
return vfprintf(os, format_str, vargs);
|
|
||||||
}
|
}
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Formatting library for C++ - time formatting
|
// Formatting library for C++ - time formatting
|
||||||
//
|
//
|
||||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// For the license information refer to format.h.
|
// For the license information refer to format.h.
|
||||||
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
|
|||||||
inline null<> localtime_s(...) { return null<>(); }
|
inline null<> localtime_s(...) { return null<>(); }
|
||||||
inline null<> gmtime_r(...) { return null<>(); }
|
inline null<> gmtime_r(...) { return null<>(); }
|
||||||
inline null<> gmtime_s(...) { return null<>(); }
|
inline null<> gmtime_s(...) { return null<>(); }
|
||||||
}
|
} // namespace internal
|
||||||
|
|
||||||
// Thread-safe replacement for std::localtime
|
// Thread-safe replacement for std::localtime
|
||||||
inline std::tm localtime(std::time_t time) {
|
inline std::tm localtime(std::time_t time) {
|
||||||
@ -46,18 +47,20 @@ inline std::tm localtime(std::time_t time) {
|
|||||||
|
|
||||||
bool fallback(int res) { return res == 0; }
|
bool fallback(int res) { return res == 0; }
|
||||||
|
|
||||||
|
#if !FMT_MSC_VER
|
||||||
bool fallback(internal::null<>) {
|
bool fallback(internal::null<>) {
|
||||||
using namespace fmt::internal;
|
using namespace fmt::internal;
|
||||||
std::tm *tm = std::localtime(&time_);
|
std::tm *tm = std::localtime(&time_);
|
||||||
if (tm) tm_ = *tm;
|
if (tm) tm_ = *tm;
|
||||||
return tm != FMT_NULL;
|
return tm != FMT_NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
dispatcher lt(time);
|
dispatcher lt(time);
|
||||||
if (lt.run())
|
|
||||||
return lt.tm_;
|
|
||||||
// Too big time values may be unsupported.
|
// Too big time values may be unsupported.
|
||||||
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_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thread-safe replacement for std::gmtime
|
// Thread-safe replacement for std::gmtime
|
||||||
@ -82,17 +85,19 @@ inline std::tm gmtime(std::time_t time) {
|
|||||||
|
|
||||||
bool fallback(int res) { return res == 0; }
|
bool fallback(int res) { return res == 0; }
|
||||||
|
|
||||||
|
#if !FMT_MSC_VER
|
||||||
bool fallback(internal::null<>) {
|
bool fallback(internal::null<>) {
|
||||||
std::tm *tm = std::gmtime(&time_);
|
std::tm *tm = std::gmtime(&time_);
|
||||||
if (tm) tm_ = *tm;
|
if (tm) tm_ = *tm;
|
||||||
return tm != FMT_NULL;
|
return tm != FMT_NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
dispatcher gt(time);
|
dispatcher gt(time);
|
||||||
if (gt.run())
|
|
||||||
return gt.tm_;
|
|
||||||
// Too big time values may be unsupported.
|
// Too big time values may be unsupported.
|
||||||
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_;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
@ -111,22 +116,21 @@ template <typename Char>
|
|||||||
struct formatter<std::tm, Char> {
|
struct formatter<std::tm, Char> {
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
|
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
|
||||||
auto it = internal::null_terminating_iterator<Char>(ctx);
|
auto it = ctx.begin();
|
||||||
if (*it == ':')
|
if (it != ctx.end() && *it == ':')
|
||||||
++it;
|
++it;
|
||||||
auto end = it;
|
auto end = it;
|
||||||
while (*end && *end != '}')
|
while (end != ctx.end() && *end != '}')
|
||||||
++end;
|
++end;
|
||||||
tm_format.reserve(end - it + 1);
|
tm_format.reserve(internal::to_unsigned(end - it + 1));
|
||||||
using internal::pointer_from;
|
tm_format.append(it, end);
|
||||||
tm_format.append(pointer_from(it), pointer_from(end));
|
|
||||||
tm_format.push_back('\0');
|
tm_format.push_back('\0');
|
||||||
return pointer_from(end);
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
|
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
|
||||||
internal::basic_buffer<Char> &buf = internal::get_container(ctx.out());
|
basic_memory_buffer<Char> buf;
|
||||||
std::size_t start = buf.size();
|
std::size_t start = buf.size();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
std::size_t size = buf.capacity() - start;
|
std::size_t size = buf.capacity() - start;
|
||||||
@ -146,7 +150,7 @@ struct formatter<std::tm, Char> {
|
|||||||
const std::size_t MIN_GROWTH = 10;
|
const std::size_t MIN_GROWTH = 10;
|
||||||
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
|
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
|
||||||
}
|
}
|
||||||
return ctx.out();
|
return std::copy(buf.begin(), buf.end(), ctx.out());
|
||||||
}
|
}
|
||||||
|
|
||||||
basic_memory_buffer<Char> tm_format;
|
basic_memory_buffer<Char> tm_format;
|
||||||
|
Loading…
Reference in New Issue
Block a user