summaryrefslogtreecommitdiff
path: root/src/third_party/fmt
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2019-06-28 15:56:59 -0400
committerBilly Donahue <billy.donahue@mongodb.com>2019-07-02 12:44:07 -0400
commitac0e818b74ecdfb02bab1ea73e4f894b634184bd (patch)
tree6d5391a61001e9579a0981f2aa1c8c433b38d050 /src/third_party/fmt
parent2bc1da6a3d84551d7ae035320706621fabe341ae (diff)
downloadmongo-ac0e818b74ecdfb02bab1ea73e4f894b634184bd.tar.gz
SERVER-41495 upgrade libfmt to fix a %g issue
update and run fmt/scripts/import.sh rewrite HostAndPort formatter to avoid now-internal fmt::writer fix merge
Diffstat (limited to 'src/third_party/fmt')
-rw-r--r--src/third_party/fmt/dist/include/fmt/chrono.h226
-rw-r--r--src/third_party/fmt/dist/include/fmt/color.h48
-rw-r--r--src/third_party/fmt/dist/include/fmt/core.h1055
-rw-r--r--src/third_party/fmt/dist/include/fmt/format-inl.h231
-rw-r--r--src/third_party/fmt/dist/include/fmt/format.h866
-rw-r--r--src/third_party/fmt/dist/include/fmt/locale.h45
-rw-r--r--src/third_party/fmt/dist/include/fmt/ostream.h44
-rw-r--r--src/third_party/fmt/dist/include/fmt/posix.h16
-rw-r--r--src/third_party/fmt/dist/include/fmt/prepare.h95
-rw-r--r--src/third_party/fmt/dist/include/fmt/printf.h142
-rw-r--r--src/third_party/fmt/dist/include/fmt/ranges.h28
-rw-r--r--src/third_party/fmt/dist/include/fmt/time.h15
-rw-r--r--src/third_party/fmt/dist/src/format.cc38
-rw-r--r--src/third_party/fmt/dist/src/posix.cc4
-rwxr-xr-xsrc/third_party/fmt/scripts/import.sh2
15 files changed, 1373 insertions, 1482 deletions
diff --git a/src/third_party/fmt/dist/include/fmt/chrono.h b/src/third_party/fmt/dist/include/fmt/chrono.h
index 0a1dab317ee..f47ff75345a 100644
--- a/src/third_party/fmt/dist/include/fmt/chrono.h
+++ b/src/third_party/fmt/dist/include/fmt/chrono.h
@@ -42,7 +42,7 @@ inline std::tm localtime(std::time_t time) {
return handle(localtime_r(&time_, &tm_));
}
- bool handle(std::tm* tm) { return tm != FMT_NULL; }
+ bool handle(std::tm* tm) { return tm != nullptr; }
bool handle(internal::null<>) {
using namespace fmt::internal;
@@ -56,7 +56,7 @@ inline std::tm localtime(std::time_t time) {
using namespace fmt::internal;
std::tm* tm = std::localtime(&time_);
if (tm) tm_ = *tm;
- return tm != FMT_NULL;
+ return tm != nullptr;
}
#endif
};
@@ -79,7 +79,7 @@ inline std::tm gmtime(std::time_t time) {
return handle(gmtime_r(&time_, &tm_));
}
- bool handle(std::tm* tm) { return tm != FMT_NULL; }
+ bool handle(std::tm* tm) { return tm != nullptr; }
bool handle(internal::null<>) {
using namespace fmt::internal;
@@ -92,7 +92,7 @@ inline std::tm gmtime(std::time_t time) {
bool fallback(internal::null<>) {
std::tm* tm = std::gmtime(&time_);
if (tm) tm_ = *tm;
- return tm != FMT_NULL;
+ return tm != nullptr;
}
#endif
};
@@ -157,7 +157,7 @@ template <typename Char> struct formatter<std::tm, Char> {
namespace internal {
template <typename Period> FMT_CONSTEXPR const char* get_units() {
- return FMT_NULL;
+ return nullptr;
}
template <> FMT_CONSTEXPR const char* get_units<std::atto>() { return "as"; }
template <> FMT_CONSTEXPR const char* get_units<std::femto>() { return "fs"; }
@@ -348,59 +348,107 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
}
struct chrono_format_checker {
- void report_no_date() { FMT_THROW(format_error("no date")); }
+ FMT_NORETURN void report_no_date() { FMT_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(); }
+ FMT_NORETURN void on_abbr_weekday() { report_no_date(); }
+ FMT_NORETURN void on_full_weekday() { report_no_date(); }
+ FMT_NORETURN void on_dec0_weekday(numeric_system) { report_no_date(); }
+ FMT_NORETURN void on_dec1_weekday(numeric_system) { report_no_date(); }
+ FMT_NORETURN void on_abbr_month() { report_no_date(); }
+ FMT_NORETURN 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(); }
+ FMT_NORETURN void on_datetime(numeric_system) { report_no_date(); }
+ FMT_NORETURN void on_loc_date(numeric_system) { report_no_date(); }
+ FMT_NORETURN void on_loc_time(numeric_system) { report_no_date(); }
+ FMT_NORETURN void on_us_date() { report_no_date(); }
+ FMT_NORETURN 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_duration_value() {}
void on_duration_unit() {}
- void on_utc_offset() { report_no_date(); }
- void on_tz_name() { report_no_date(); }
+ FMT_NORETURN void on_utc_offset() { report_no_date(); }
+ FMT_NORETURN 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");
+template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
+inline bool isnan(T) {
+ return false;
+}
+template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
+inline bool isnan(T value) {
+ return std::isnan(value);
+}
+
+// Convers value to int and checks that it's in the range [0, upper).
+template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
+inline int to_nonnegative_int(T value, int upper) {
+ FMT_ASSERT(value >= 0 && value <= upper, "invalid value");
+ (void)upper;
+ return static_cast<int>(value);
+}
+template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
+inline int to_nonnegative_int(T value, int upper) {
+ FMT_ASSERT(
+ std::isnan(value) || (value >= 0 && value <= static_cast<T>(upper)),
+ "invalid value");
+ (void)upper;
return static_cast<int>(value);
}
+template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
+inline T mod(T x, int y) {
+ return x % y;
+}
+template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
+inline T mod(T x, int y) {
+ return std::fmod(x, y);
+}
+
+// If T is an integral type, maps T to its unsigned counterpart, otherwise
+// leaves it unchanged (unlike std::make_unsigned).
+template <typename T, bool INTEGRAL = std::is_integral<T>::value>
+struct make_unsigned_or_unchanged {
+ using type = T;
+};
+
+template <typename T> struct make_unsigned_or_unchanged<T, true> {
+ using type = typename std::make_unsigned<T>::type;
+};
+
+template <typename Rep, typename Period,
+ FMT_ENABLE_IF(std::is_integral<Rep>::value)>
+inline std::chrono::duration<Rep, std::milli> get_milliseconds(
+ std::chrono::duration<Rep, Period> d) {
+ auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
+ return std::chrono::duration_cast<std::chrono::milliseconds>(d - s);
+}
+
+template <typename Rep, typename Period,
+ FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
+inline std::chrono::duration<Rep, std::milli> get_milliseconds(
+ std::chrono::duration<Rep, Period> d) {
+ auto ms = mod(d.count() * Period::num / Period::den * 1000, 1000);
+ return std::chrono::duration<Rep, std::milli>(static_cast<Rep>(ms));
+}
+
template <typename Rep, typename OutputIt>
-OutputIt static format_chrono_duration_value(OutputIt out, Rep val,
- int precision) {
- if (precision < 0) {
- return format_to(out, std::is_floating_point<Rep>::value ? "{:g}" : "{}",
- val);
- }
- return format_to(out, "{:.{}f}", val, precision);
+OutputIt format_chrono_duration_value(OutputIt out, Rep val, int precision) {
+ if (precision >= 0) return format_to(out, "{:.{}f}", val, precision);
+ return format_to(out, std::is_floating_point<Rep>::value ? "{:g}" : "{}",
+ val);
}
template <typename Period, typename OutputIt>
static OutputIt format_chrono_duration_unit(OutputIt out) {
- if (const char* unit = get_units<Period>())
- return format_to(out, "{}", unit);
- else if (Period::den == 1)
- return format_to(out, "[{}]s", Period::num);
- else
- return format_to(out, "[{}/{}]s", Period::num, Period::den);
+ if (const char* unit = get_units<Period>()) return format_to(out, "{}", unit);
+ if (Period::den == 1) return format_to(out, "[{}]s", Period::num);
+ return format_to(out, "[{}/{}]s", Period::num, Period::den);
}
template <typename FormatContext, typename OutputIt, typename Rep,
@@ -409,48 +457,69 @@ struct chrono_formatter {
FormatContext& context;
OutputIt out;
int precision;
- Rep val;
- typedef std::chrono::duration<Rep, std::milli> milliseconds;
- std::chrono::seconds s;
- milliseconds ms;
+ // rep is unsigned to avoid overflow.
+ using rep =
+ conditional_t<std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int),
+ unsigned, typename make_unsigned_or_unchanged<Rep>::type>;
+ rep val;
+ typedef std::chrono::duration<rep> seconds;
+ seconds s;
+ typedef std::chrono::duration<rep, std::milli> milliseconds;
+ bool negative;
typedef typename FormatContext::char_type char_type;
explicit chrono_formatter(FormatContext& ctx, OutputIt o,
std::chrono::duration<Rep, Period> d)
- : context(ctx),
- out(o),
- val(d.count()),
- s(std::chrono::duration_cast<std::chrono::seconds>(d)),
- ms(std::chrono::duration_cast<milliseconds>(d - s)) {}
+ : context(ctx), out(o), val(d.count()), negative(false) {
+ if (d.count() < 0) {
+ val = -val;
+ negative = true;
+ }
+ s = std::chrono::duration_cast<seconds>(
+ std::chrono::duration<rep, Period>(val));
+ }
- int hour() const { return to_int((s.count() / 3600) % 24); }
+ Rep hour() const { return static_cast<Rep>(mod((s.count() / 3600), 24)); }
- int hour12() const {
- auto hour = to_int((s.count() / 3600) % 12);
- return hour > 0 ? hour : 12;
+ Rep hour12() const {
+ Rep hour = static_cast<Rep>(mod((s.count() / 3600), 12));
+ return hour <= 0 ? 12 : hour;
}
- int minute() const { return to_int((s.count() / 60) % 60); }
- int second() const { return to_int(s.count() % 60); }
+ Rep minute() const { return static_cast<Rep>(mod((s.count() / 60), 60)); }
+ Rep second() const { return static_cast<Rep>(mod(s.count(), 60)); }
std::tm time() const {
auto time = std::tm();
- time.tm_hour = hour();
- time.tm_min = minute();
- time.tm_sec = second();
+ time.tm_hour = to_nonnegative_int(hour(), 24);
+ time.tm_min = to_nonnegative_int(minute(), 60);
+ time.tm_sec = to_nonnegative_int(second(), 60);
return time;
}
- void write(int value, int width) {
+ void write_sign() {
+ if (negative) {
+ *out++ = '-';
+ negative = false;
+ }
+ }
+
+ void write(Rep value, int width) {
+ write_sign();
+ if (isnan(value)) return write_nan();
typedef typename int_traits<int>::main_type main_type;
- main_type n = to_unsigned(value);
+ main_type n = to_unsigned(
+ to_nonnegative_int(value, (std::numeric_limits<int>::max)()));
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 write_nan() { std::copy_n("nan", 3, out); }
+
void format_localized(const tm& time, const char* format) {
+ if (isnan(val)) return write_nan();
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;
@@ -482,35 +551,36 @@ struct chrono_formatter {
void on_24_hour(numeric_system ns) {
if (ns == numeric_system::standard) return write(hour(), 2);
auto time = tm();
- time.tm_hour = hour();
+ time.tm_hour = to_nonnegative_int(hour(), 24);
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();
+ time.tm_hour = to_nonnegative_int(hour12(), 12);
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();
+ time.tm_min = to_nonnegative_int(minute(), 60);
format_localized(time, "%OM");
}
void on_second(numeric_system ns) {
if (ns == numeric_system::standard) {
write(second(), 2);
+ auto ms = get_milliseconds(std::chrono::duration<Rep, Period>(val));
if (ms != std::chrono::milliseconds(0)) {
*out++ = '.';
- write(to_int(ms.count()), 3);
+ write(ms.count(), 3);
}
return;
}
auto time = tm();
- time.tm_sec = second();
+ time.tm_sec = to_nonnegative_int(second(), 60);
format_localized(time, "%OS");
}
@@ -531,6 +601,7 @@ struct chrono_formatter {
void on_am_pm() { format_localized(time(), "%p"); }
void on_duration_value() {
+ write_sign();
out = format_chrono_duration_value(out, val, precision);
}
@@ -585,18 +656,20 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
}
};
- public:
- formatter() : spec(), precision(-1) {}
+ typedef typename basic_parse_context<Char>::iterator iterator;
+ struct parse_range {
+ iterator begin;
+ iterator end;
+ };
- FMT_CONSTEXPR auto parse(basic_parse_context<Char>& ctx)
- -> decltype(ctx.begin()) {
+ FMT_CONSTEXPR parse_range do_parse(basic_parse_context<Char>& ctx) {
auto begin = ctx.begin(), end = ctx.end();
- if (begin == end) return begin;
+ if (begin == end || *begin == '}') return {begin, begin};
spec_handler handler{*this, ctx, format_str};
begin = internal::parse_align(begin, end, handler);
- if (begin == end) return begin;
+ if (begin == end) return {begin, begin};
begin = internal::parse_width(begin, end, handler);
- if (begin == end) return begin;
+ if (begin == end) return {begin, begin};
if (*begin == '.') {
if (std::is_floating_point<Rep>::value)
begin = internal::parse_precision(begin, end, handler);
@@ -604,9 +677,18 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
handler.on_error("precision not allowed for this argument type");
}
end = parse_chrono_format(begin, end, internal::chrono_format_checker());
- format_str =
- basic_string_view<Char>(&*begin, internal::to_unsigned(end - begin));
- return end;
+ return {begin, end};
+ }
+
+ public:
+ formatter() : spec(), precision(-1) {}
+
+ FMT_CONSTEXPR auto parse(basic_parse_context<Char>& ctx)
+ -> decltype(ctx.begin()) {
+ auto range = do_parse(ctx);
+ format_str = basic_string_view<Char>(
+ &*range.begin, internal::to_unsigned(range.end - range.begin));
+ return range.end;
}
template <typename FormatContext>
@@ -616,7 +698,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
// is not specified.
basic_memory_buffer<Char> buf;
auto out = std::back_inserter(buf);
- typedef output_range<decltype(ctx.out()), Char> range;
+ using range = internal::output_range<decltype(ctx.out()), Char>;
basic_writer<range> w(range(ctx.out()));
internal::handle_dynamic_spec<internal::width_checker>(
spec.width_, width_ref, ctx, format_str.begin());
diff --git a/src/third_party/fmt/dist/include/fmt/color.h b/src/third_party/fmt/dist/include/fmt/color.h
index b29ab082192..f1683a7181f 100644
--- a/src/third_party/fmt/dist/include/fmt/color.h
+++ b/src/third_party/fmt/dist/include/fmt/color.h
@@ -518,17 +518,10 @@ inline void reset_color(basic_memory_buffer<Char>& buffer) FMT_NOEXCEPT {
buffer.append(begin, end);
}
-// The following specialization 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 {};
-
template <typename Char>
-std::basic_string<Char> vformat(
- const text_style& ts, basic_string_view<Char> format_str,
- basic_format_args<typename buffer_context<Char>::type> args) {
+std::basic_string<Char> vformat(const text_style& ts,
+ basic_string_view<Char> format_str,
+ basic_format_args<buffer_context<Char> > args) {
basic_memory_buffer<Char> buffer;
bool has_style = false;
if (ts.has_emphasis()) {
@@ -556,9 +549,9 @@ std::basic_string<Char> vformat(
}
} // namespace internal
-template <typename S, typename Char = typename internal::char_t<S>::type>
+template <typename S, typename Char = char_t<S> >
void vprint(std::FILE* f, const text_style& ts, const S& format,
- basic_format_args<typename buffer_context<Char>::type> args) {
+ basic_format_args<buffer_context<Char> > args) {
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
@@ -587,15 +580,14 @@ void vprint(std::FILE* f, const text_style& ts, const S& format,
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
*/
-template <typename String, typename... Args,
- FMT_ENABLE_IF(internal::is_string<String>::value)>
-void print(std::FILE* f, const text_style& ts, const String& format_str,
+template <typename S, typename... Args,
+ FMT_ENABLE_IF(internal::is_string<S>::value)>
+void print(std::FILE* f, const text_style& ts, const S& 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));
+ using context = buffer_context<char_t<S> >;
+ format_arg_store<context, Args...> as{args...};
+ vprint(f, ts, format_str, basic_format_args<context>(as));
}
/**
@@ -605,17 +597,16 @@ void print(std::FILE* f, const text_style& ts, const String& format_str,
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
*/
-template <typename String, typename... Args,
- FMT_ENABLE_IF(internal::is_string<String>::value)>
-void print(const text_style& ts, const String& format_str,
- const Args&... args) {
+template <typename S, typename... Args,
+ FMT_ENABLE_IF(internal::is_string<S>::value)>
+void print(const text_style& ts, const S& format_str, const Args&... args) {
return print(stdout, ts, format_str, args...);
}
-template <typename S, typename Char = FMT_CHAR(S)>
+template <typename S, typename Char = char_t<S> >
inline std::basic_string<Char> vformat(
const text_style& ts, const S& format_str,
- basic_format_args<typename buffer_context<Char>::type> args) {
+ basic_format_args<buffer_context<Char> > args) {
return internal::vformat(ts, to_string_view(format_str), args);
}
@@ -631,10 +622,9 @@ inline std::basic_string<Char> vformat(
"The answer is {}", 42);
\endrst
*/
-template <typename S, typename... Args>
-inline std::basic_string<FMT_CHAR(S)> format(const text_style& ts,
- const S& format_str,
- const Args&... args) {
+template <typename S, typename... Args, typename Char = char_t<S> >
+inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
+ const Args&... args) {
return internal::vformat(ts, to_string_view(format_str),
{internal::make_args_checked(format_str, args...)});
}
diff --git a/src/third_party/fmt/dist/include/fmt/core.h b/src/third_party/fmt/dist/include/fmt/core.h
index 5ba58e1af68..52c812bedcc 100644
--- a/src/third_party/fmt/dist/include/fmt/core.h
+++ b/src/third_party/fmt/dist/include/fmt/core.h
@@ -70,16 +70,6 @@
# define FMT_CONSTEXPR_DECL
#endif
-#ifndef FMT_USE_CONSTEXPR11
-# define FMT_USE_CONSTEXPR11 \
- (FMT_USE_CONSTEXPR || FMT_GCC_VERSION >= 406 || FMT_MSC_VER >= 1900)
-#endif
-#if FMT_USE_CONSTEXPR11
-# define FMT_CONSTEXPR11 constexpr
-#else
-# define FMT_CONSTEXPR11
-#endif
-
#ifndef FMT_OVERRIDE
# if FMT_HAS_FEATURE(cxx_override) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900
@@ -89,28 +79,6 @@
# endif
#endif
-#if FMT_HAS_FEATURE(cxx_explicit_conversions) || FMT_GCC_VERSION >= 405 || \
- FMT_MSC_VER >= 1800
-# define FMT_USE_EXPLICIT 1
-# define FMT_EXPLICIT explicit
-#else
-# define FMT_USE_EXPLICIT 0
-# define FMT_EXPLICIT
-#endif
-
-#ifndef FMT_NULL
-# if FMT_HAS_FEATURE(cxx_nullptr) || \
- (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600
-# define FMT_NULL nullptr
-# define FMT_USE_NULLPTR 1
-# else
-# define FMT_NULL NULL
-# endif
-#endif
-#ifndef FMT_USE_NULLPTR
-# define FMT_USE_NULLPTR 0
-#endif
-
// Check if exceptions are disabled.
#ifndef FMT_EXCEPTIONS
# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \
@@ -143,6 +111,13 @@
# endif
#endif
+// [[noreturn]] is disabled on MSVC because of bogus unreachable code warnings.
+#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER
+# define FMT_NORETURN [[noreturn]]
+#else
+# define FMT_NORETURN
+#endif
+
#ifndef FMT_DEPRECATED
# if (FMT_HAS_CPP_ATTRIBUTE(deprecated) && __cplusplus >= 201402L) || \
FMT_MSC_VER >= 1900
@@ -182,11 +157,21 @@
# define FMT_API __declspec(dllexport)
# elif defined(FMT_SHARED)
# define FMT_API __declspec(dllimport)
+# define FMT_EXTERN_TEMPLATE_API FMT_API
# endif
#endif
#ifndef FMT_API
# define FMT_API
#endif
+#ifndef FMT_EXTERN_TEMPLATE_API
+# define FMT_EXTERN_TEMPLATE_API
+#endif
+
+#ifndef FMT_HEADER_ONLY
+# define FMT_EXTERN extern
+#else
+# define FMT_EXTERN
+#endif
#ifndef FMT_ASSERT
# define FMT_ASSERT(condition, message) assert((condition) && message)
@@ -197,40 +182,39 @@
(__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
# include <string_view>
-# define FMT_STRING_VIEW std::basic_string_view
-#elif FMT_HAS_INCLUDE(<experimental / string_view>) && __cplusplus >= 201402L
+# define FMT_USE_STRING_VIEW
+#elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L
# include <experimental/string_view>
-# define FMT_STRING_VIEW std::experimental::basic_string_view
+# define FMT_USE_EXPERIMENTAL_STRING_VIEW
#endif
-// std::result_of is defined in <functional> in gcc 4.4.
-#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404
-# include <functional>
-#endif
-
-// An enable_if helper to be used in template parameters. enable_if in template
-// parameters results in much shorter symbols: https://godbolt.org/z/sWw4vP.
-#define FMT_ENABLE_IF(...) typename std::enable_if<__VA_ARGS__, int>::type = 0
-
FMT_BEGIN_NAMESPACE
-namespace internal {
-// An implementation of declval for pre-C++11 compilers such as gcc 4.
+// Implementations of enable_if_t and other types for pre-C++14 systems.
+template <bool B, class T = void>
+using enable_if_t = typename std::enable_if<B, T>::type;
+template <bool B, class T, class F>
+using conditional_t = typename std::conditional<B, T, F>::type;
+template <bool B> using bool_constant = std::integral_constant<bool, B>;
template <typename T>
-typename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT;
+using remove_reference_t = typename std::remove_reference<T>::type;
+
+struct monostate {};
-template <typename> struct result_of;
+// An enable_if helper to be used in template parameters which results in much
+// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
+// to workaround a bug in MSVC 2019 (see #1140 and #1186).
+#define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0
-#if (__cplusplus >= 201703L || \
- (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)) && \
- __cpp_lib_is_invocable >= 201703L
-template <typename F, typename... Args>
-struct result_of<F(Args...)> : std::invoke_result<F, Args...> {};
+namespace internal {
+
+#if defined(FMT_USE_STRING_VIEW)
+template <typename Char> using std_string_view = std::basic_string_view<Char>;
+#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
+template <typename Char>
+using std_string_view = std::experimental::basic_string_view<Char>;
#else
-// A workaround for gcc 4.4 that doesn't allow F to be a reference.
-template <typename F, typename... Args>
-struct result_of<F(Args...)>
- : std::result_of<typename std::remove_reference<F>::type(Args...)> {};
+template <typename T> struct std_string_view {};
#endif
// Casts nonnegative integer to unsigned.
@@ -239,138 +223,6 @@ FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
FMT_ASSERT(value >= 0, "negative value");
return static_cast<typename std::make_unsigned<Int>::type>(value);
}
-
-/** A contiguous memory buffer with an optional growing ability. */
-template <typename T> class basic_buffer {
- private:
- basic_buffer(const basic_buffer&) = delete;
- void operator=(const basic_buffer&) = delete;
-
- T* ptr_;
- std::size_t size_;
- std::size_t capacity_;
-
- protected:
- // Don't initialize ptr_ since it is not accessed to save a few cycles.
- basic_buffer(std::size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {}
-
- basic_buffer(T* p = FMT_NULL, std::size_t sz = 0,
- std::size_t cap = 0) FMT_NOEXCEPT : ptr_(p),
- size_(sz),
- capacity_(cap) {}
-
- /** Sets the buffer data and capacity. */
- void set(T* buf_data, std::size_t buf_capacity) FMT_NOEXCEPT {
- ptr_ = buf_data;
- capacity_ = buf_capacity;
- }
-
- /** Increases the buffer capacity to hold at least *capacity* elements. */
- virtual void grow(std::size_t capacity) = 0;
-
- public:
- typedef T value_type;
- typedef const T& const_reference;
-
- virtual ~basic_buffer() {}
-
- T* begin() FMT_NOEXCEPT { return ptr_; }
- T* end() FMT_NOEXCEPT { return ptr_ + size_; }
-
- /** Returns the size of this buffer. */
- std::size_t size() const FMT_NOEXCEPT { return size_; }
-
- /** Returns the capacity of this buffer. */
- std::size_t capacity() const FMT_NOEXCEPT { return capacity_; }
-
- /** Returns a pointer to the buffer data. */
- T* data() FMT_NOEXCEPT { return ptr_; }
-
- /** Returns a pointer to the buffer data. */
- const T* data() const FMT_NOEXCEPT { return ptr_; }
-
- /**
- Resizes the buffer. If T is a POD type new elements may not be initialized.
- */
- void resize(std::size_t new_size) {
- reserve(new_size);
- size_ = new_size;
- }
-
- /** Clears this buffer. */
- void clear() { size_ = 0; }
-
- /** Reserves space to store at least *capacity* elements. */
- void reserve(std::size_t new_capacity) {
- if (new_capacity > capacity_) grow(new_capacity);
- }
-
- void push_back(const T& value) {
- reserve(size_ + 1);
- ptr_[size_++] = value;
- }
-
- /** Appends data to the end of the buffer. */
- template <typename U> void append(const U* begin, const U* end);
-
- T& operator[](std::size_t index) { return ptr_[index]; }
- const T& operator[](std::size_t index) const { return ptr_[index]; }
-};
-
-typedef basic_buffer<char> buffer;
-typedef basic_buffer<wchar_t> wbuffer;
-
-// A container-backed buffer.
-template <typename Container>
-class container_buffer : public basic_buffer<typename Container::value_type> {
- private:
- Container& container_;
-
- protected:
- void grow(std::size_t capacity) FMT_OVERRIDE {
- container_.resize(capacity);
- this->set(&container_[0], capacity);
- }
-
- public:
- explicit container_buffer(Container& c)
- : basic_buffer<typename Container::value_type>(c.size()), container_(c) {}
-};
-
-// Extracts a reference to the container from back_insert_iterator.
-template <typename Container>
-inline Container& get_container(std::back_insert_iterator<Container> it) {
- typedef std::back_insert_iterator<Container> bi_iterator;
- struct accessor : bi_iterator {
- accessor(bi_iterator iter) : bi_iterator(iter) {}
- using bi_iterator::container;
- };
- return *accessor(it).container;
-}
-
-struct error_handler {
- FMT_CONSTEXPR error_handler() {}
- FMT_CONSTEXPR error_handler(const error_handler&) {}
-
- // This function is intentionally not constexpr to give a compile-time error.
- FMT_API void on_error(const char* message);
-};
-
-// GCC 4.6.x cannot expand `T...`.
-#if FMT_GCC_VERSION && FMT_GCC_VERSION < 407
-typedef char yes[1];
-typedef char no[2];
-
-template <typename T, typename V> struct is_constructible {
- template <typename U> static yes& test(int (*)[sizeof(new U(declval<V>()))]);
- template <typename U> static no& test(...);
- enum { value = sizeof(test<T>(FMT_NULL)) == sizeof(yes) };
-};
-#else
-template <typename... T>
-struct is_constructible : std::is_constructible<T...> {};
-#endif
-struct dummy_formatter_arg {}; // Workaround broken is_constructible in MSVC.
} // namespace internal
/**
@@ -386,10 +238,10 @@ template <typename Char> class basic_string_view {
size_t size_;
public:
- typedef Char char_type;
- typedef const Char* iterator;
+ using char_type = Char;
+ using iterator = const Char*;
- FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(FMT_NULL), size_(0) {}
+ FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {}
/** Constructs a string reference object from a C string and a size. */
FMT_CONSTEXPR basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT
@@ -411,11 +263,11 @@ template <typename Char> class basic_string_view {
FMT_NOEXCEPT : data_(s.data()),
size_(s.size()) {}
-#ifdef FMT_STRING_VIEW
- FMT_CONSTEXPR basic_string_view(FMT_STRING_VIEW<Char> s) FMT_NOEXCEPT
- : data_(s.data()),
- size_(s.size()) {}
-#endif
+ template <
+ typename S,
+ FMT_ENABLE_IF(std::is_same<S, internal::std_string_view<Char>>::value)>
+ FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()),
+ size_(s.size()) {}
/** Returns a pointer to the string data. */
FMT_CONSTEXPR const Char* data() const { return data_; }
@@ -460,33 +312,40 @@ template <typename Char> class basic_string_view {
}
};
-typedef basic_string_view<char> string_view;
-typedef basic_string_view<wchar_t> wstring_view;
+using string_view = basic_string_view<char>;
+using wstring_view = basic_string_view<wchar_t>;
+
+#ifndef __cpp_char8_t
+// A UTF-8 code unit type.
+enum char8_t : unsigned char {};
+#endif
+
+/** Specifies if ``T`` is a character type. Can be specialized by users. */
+template <typename T> struct is_char : std::false_type {};
+template <> struct is_char<char> : std::true_type {};
+template <> struct is_char<wchar_t> : std::true_type {};
+template <> struct is_char<char8_t> : std::true_type {};
+template <> struct is_char<char16_t> : std::true_type {};
+template <> struct is_char<char32_t> : std::true_type {};
/**
\rst
- The function ``to_string_view`` adapts non-intrusively any kind of string or
- string-like type if the user provides a (possibly templated) overload of
- ``to_string_view`` which takes an instance of the string class
- ``StringType<Char>`` and returns a ``fmt::basic_string_view<Char>``.
- The conversion function must live in the very same namespace as
- ``StringType<Char>`` to be picked up by ADL. Non-templated string types
- like f.e. QString must return a ``basic_string_view`` with a fixed matching
- char type.
+ Returns a string view of `s`. In order to add custom string type support to
+ {fmt} provide an overload of `to_string_view` for it in the same namespace as
+ the type for the argument-dependent lookup to work.
**Example**::
namespace my_ns {
- inline string_view to_string_view(const my_string &s) {
+ inline string_view to_string_view(const my_string& s) {
return {s.data(), s.length()};
}
}
-
std::string message = fmt::format(my_string("The answer is {}"), 42);
\endrst
*/
-template <typename Char>
-inline basic_string_view<Char> to_string_view(basic_string_view<Char> s) {
+template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
+inline basic_string_view<Char> to_string_view(const Char* s) {
return s;
}
@@ -497,16 +356,16 @@ inline basic_string_view<Char> to_string_view(
}
template <typename Char>
-inline basic_string_view<Char> to_string_view(const Char* s) {
+inline basic_string_view<Char> to_string_view(basic_string_view<Char> s) {
return s;
}
-#ifdef FMT_STRING_VIEW
-template <typename Char>
-inline basic_string_view<Char> to_string_view(FMT_STRING_VIEW<Char> s) {
+template <typename Char,
+ FMT_ENABLE_IF(!std::is_empty<internal::std_string_view<Char>>::value)>
+inline basic_string_view<Char> to_string_view(
+ internal::std_string_view<Char> s) {
return s;
}
-#endif
// A base class for compile-time strings. It is defined in the fmt namespace to
// make formatting functions visible via ADL, e.g. format(fmt("{}"), 42).
@@ -516,11 +375,39 @@ template <typename S>
struct is_compile_string : std::is_base_of<compile_string, S> {};
template <typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
-FMT_CONSTEXPR basic_string_view<typename S::char_type> to_string_view(
- const S& s) {
+constexpr basic_string_view<typename S::char_type> to_string_view(const S& s) {
return s;
}
+namespace internal {
+void to_string_view(...);
+using fmt::v5::to_string_view;
+
+// Specifies whether S is a string type convertible to fmt::basic_string_view.
+// It should be a constexpr function but MSVC 2017 fails to compile it in
+// enable_if and MSVC 2015 fails to compile it as an alias template.
+template <typename S>
+struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> {
+};
+
+template <typename S, typename = void> struct char_t_impl {};
+template <typename S> struct char_t_impl<S, enable_if_t<is_string<S>::value>> {
+ using result = decltype(to_string_view(std::declval<S>()));
+ using type = typename result::char_type;
+};
+
+struct error_handler {
+ FMT_CONSTEXPR error_handler() {}
+ FMT_CONSTEXPR error_handler(const error_handler&) {}
+
+ // This function is intentionally not constexpr to give a compile-time error.
+ FMT_NORETURN FMT_API void on_error(const char* message);
+};
+} // namespace internal
+
+/** String's character type. */
+template <typename S> using char_t = typename internal::char_t_impl<S>::type;
+
// Parsing context consisting of a format string range being parsed and an
// argument counter for automatic indexing.
template <typename Char, typename ErrorHandler = internal::error_handler>
@@ -530,8 +417,8 @@ class basic_parse_context : private ErrorHandler {
int next_arg_id_;
public:
- typedef Char char_type;
- typedef typename basic_string_view<Char>::iterator iterator;
+ using char_type = Char;
+ using iterator = typename basic_string_view<Char>::iterator;
explicit FMT_CONSTEXPR basic_parse_context(basic_string_view<Char> format_str,
ErrorHandler eh = ErrorHandler())
@@ -552,7 +439,11 @@ class basic_parse_context : private ErrorHandler {
}
// Returns the next argument index.
- FMT_CONSTEXPR unsigned next_arg_id();
+ FMT_CONSTEXPR unsigned next_arg_id() {
+ if (next_arg_id_ >= 0) return internal::to_unsigned(next_arg_id_++);
+ on_error("cannot switch from manual to automatic argument indexing");
+ return 0;
+ }
FMT_CONSTEXPR bool check_arg_id(unsigned) {
if (next_arg_id_ > 0) {
@@ -572,11 +463,11 @@ class basic_parse_context : private ErrorHandler {
FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; }
};
-typedef basic_parse_context<char> format_parse_context;
-typedef basic_parse_context<wchar_t> wformat_parse_context;
+using format_parse_context = basic_parse_context<char>;
+using wformat_parse_context = basic_parse_context<wchar_t>;
-FMT_DEPRECATED typedef basic_parse_context<char> parse_context;
-FMT_DEPRECATED typedef basic_parse_context<wchar_t> wparse_context;
+using parse_context FMT_DEPRECATED = basic_parse_context<char>;
+using wparse_context FMT_DEPRECATED = basic_parse_context<wchar_t>;
template <typename Context> class basic_format_arg;
template <typename Context> class basic_format_args;
@@ -584,51 +475,139 @@ template <typename Context> class basic_format_args;
// A formatter for objects of type T.
template <typename T, typename Char = char, typename Enable = void>
struct formatter {
- explicit formatter(internal::dummy_formatter_arg);
+ // A deleted default constructor indicates a disabled formatter.
+ formatter() = delete;
};
template <typename T, typename Char, typename Enable = void>
-struct convert_to_int
- : std::integral_constant<bool, !std::is_arithmetic<T>::value &&
- std::is_convertible<T, int>::value> {};
+struct FMT_DEPRECATED convert_to_int
+ : bool_constant<!std::is_arithmetic<T>::value &&
+ std::is_convertible<T, int>::value> {};
namespace internal {
-template <typename T> struct no_formatter_error : std::false_type {};
+// Specifies if T has an enabled formatter specialization. A type can be
+// formattable even if it doesn't have a formatter e.g. via a conversion.
+template <typename T, typename Context>
+using has_formatter =
+ std::is_constructible<typename Context::template formatter_type<T>>;
-template <typename T, typename Char = char, typename Enable = void>
-struct fallback_formatter {
- static_assert(
- no_formatter_error<T>::value,
- "don't know how to format the type, include fmt/ostream.h if it provides "
- "an operator<< that should be used");
-};
+/** A contiguous memory buffer with an optional growing ability. */
+template <typename T> class buffer {
+ private:
+ buffer(const buffer&) = delete;
+ void operator=(const buffer&) = delete;
-struct dummy_string_view {
- typedef void char_type;
+ T* ptr_;
+ std::size_t size_;
+ std::size_t capacity_;
+
+ protected:
+ // Don't initialize ptr_ since it is not accessed to save a few cycles.
+ buffer(std::size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {}
+
+ buffer(T* p = nullptr, std::size_t sz = 0, std::size_t cap = 0) FMT_NOEXCEPT
+ : ptr_(p),
+ size_(sz),
+ capacity_(cap) {}
+
+ /** Sets the buffer data and capacity. */
+ void set(T* buf_data, std::size_t buf_capacity) FMT_NOEXCEPT {
+ ptr_ = buf_data;
+ capacity_ = buf_capacity;
+ }
+
+ /** Increases the buffer capacity to hold at least *capacity* elements. */
+ virtual void grow(std::size_t capacity) = 0;
+
+ public:
+ using value_type = T;
+ using const_reference = const T&;
+
+ virtual ~buffer() {}
+
+ T* begin() FMT_NOEXCEPT { return ptr_; }
+ T* end() FMT_NOEXCEPT { return ptr_ + size_; }
+
+ /** Returns the size of this buffer. */
+ std::size_t size() const FMT_NOEXCEPT { return size_; }
+
+ /** Returns the capacity of this buffer. */
+ std::size_t capacity() const FMT_NOEXCEPT { return capacity_; }
+
+ /** Returns a pointer to the buffer data. */
+ T* data() FMT_NOEXCEPT { return ptr_; }
+
+ /** Returns a pointer to the buffer data. */
+ const T* data() const FMT_NOEXCEPT { return ptr_; }
+
+ /**
+ Resizes the buffer. If T is a POD type new elements may not be initialized.
+ */
+ void resize(std::size_t new_size) {
+ reserve(new_size);
+ size_ = new_size;
+ }
+
+ /** Clears this buffer. */
+ void clear() { size_ = 0; }
+
+ /** Reserves space to store at least *capacity* elements. */
+ void reserve(std::size_t new_capacity) {
+ if (new_capacity > capacity_) grow(new_capacity);
+ }
+
+ void push_back(const T& value) {
+ reserve(size_ + 1);
+ ptr_[size_++] = value;
+ }
+
+ /** Appends data to the end of the buffer. */
+ template <typename U> void append(const U* begin, const U* end);
+
+ T& operator[](std::size_t index) { return ptr_[index]; }
+ const T& operator[](std::size_t index) const { return ptr_[index]; }
};
-dummy_string_view to_string_view(...);
-using fmt::v5::to_string_view;
-// Specifies whether S is a string type convertible to fmt::basic_string_view.
-template <typename S>
-struct is_string
- : std::integral_constant<
- bool, !std::is_same<dummy_string_view,
- decltype(to_string_view(declval<S>()))>::value> {
+// A container-backed buffer.
+template <typename Container>
+class container_buffer : public buffer<typename Container::value_type> {
+ private:
+ Container& container_;
+
+ protected:
+ void grow(std::size_t capacity) FMT_OVERRIDE {
+ container_.resize(capacity);
+ this->set(&container_[0], capacity);
+ }
+
+ public:
+ explicit container_buffer(Container& c)
+ : buffer<typename Container::value_type>(c.size()), container_(c) {}
};
-// Forward declare FILE* specialization defined in color.h
-template <> struct is_string<std::FILE*>;
-template <> struct is_string<const std::FILE*>;
+// Extracts a reference to the container from back_insert_iterator.
+template <typename Container>
+inline Container& get_container(std::back_insert_iterator<Container> it) {
+ using bi_iterator = std::back_insert_iterator<Container>;
+ struct accessor : bi_iterator {
+ accessor(bi_iterator iter) : bi_iterator(iter) {}
+ using bi_iterator::container;
+ };
+ return *accessor(it).container;
+}
-template <typename S> struct char_t {
- typedef decltype(to_string_view(declval<S>())) result;
- typedef typename result::char_type type;
+template <typename T, typename Char = char, typename Enable = void>
+struct fallback_formatter {
+ fallback_formatter() = delete;
};
-template <typename Char> struct named_arg_base;
+// Specifies if T has an enabled fallback_formatter specialization.
+template <typename T, typename Context>
+using has_fallback_formatter =
+ std::is_constructible<fallback_formatter<T, typename Context::char_type>>;
+template <typename Char> struct named_arg_base;
template <typename T, typename Char> struct named_arg;
enum type {
@@ -652,6 +631,27 @@ enum type {
custom_type
};
+// Maps core type T to the corresponding type enum constant.
+template <typename T, typename Char>
+struct type_constant : std::integral_constant<type, custom_type> {};
+
+#define FMT_TYPE_CONSTANT(Type, constant) \
+ template <typename Char> \
+ struct type_constant<Type, Char> : std::integral_constant<type, constant> {}
+
+FMT_TYPE_CONSTANT(const named_arg_base<Char>&, named_arg_type);
+FMT_TYPE_CONSTANT(int, int_type);
+FMT_TYPE_CONSTANT(unsigned, uint_type);
+FMT_TYPE_CONSTANT(long long, long_long_type);
+FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
+FMT_TYPE_CONSTANT(bool, bool_type);
+FMT_TYPE_CONSTANT(Char, char_type);
+FMT_TYPE_CONSTANT(double, double_type);
+FMT_TYPE_CONSTANT(long double, long_double_type);
+FMT_TYPE_CONSTANT(const Char*, cstring_type);
+FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
+FMT_TYPE_CONSTANT(const void*, pointer_type);
+
FMT_CONSTEXPR bool is_integral(type t) {
FMT_ASSERT(t != internal::named_arg_type, "invalid argument type");
return t > internal::none_type && t <= internal::last_integer_type;
@@ -663,82 +663,63 @@ FMT_CONSTEXPR bool is_arithmetic(type t) {
}
template <typename Char> struct string_value {
- const Char* value;
+ const Char* data;
std::size_t size;
};
template <typename Context> struct custom_value {
+ using parse_context = basic_parse_context<typename Context::char_type>;
const void* value;
- void (*format)(const void* arg,
- basic_parse_context<typename Context::char_type>& parse_ctx,
- Context& ctx);
-};
-
-template <typename T, typename Context> struct is_formattable {
- enum {
- value =
- !is_constructible<typename Context::template formatter_type<T>::type,
- internal::dummy_formatter_arg>::value
- };
+ void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx);
};
// A formatting argument value.
template <typename Context> class value {
public:
- typedef typename Context::char_type char_type;
+ using char_type = typename Context::char_type;
union {
int int_value;
unsigned uint_value;
long long long_long_value;
unsigned long long ulong_long_value;
+ bool bool_value;
+ char_type char_value;
double double_value;
long double long_double_value;
const void* pointer;
string_value<char_type> string;
- string_value<signed char> sstring;
- string_value<unsigned char> ustring;
custom_value<Context> custom;
+ const named_arg_base<char_type>* named_arg;
};
FMT_CONSTEXPR value(int val = 0) : int_value(val) {}
FMT_CONSTEXPR value(unsigned val) : uint_value(val) {}
- value(long long val) { long_long_value = val; }
- value(unsigned long long val) { ulong_long_value = val; }
- value(double val) { double_value = val; }
- value(long double val) { long_double_value = val; }
- value(const char_type* val) { string.value = val; }
- value(const signed char* val) {
- static_assert(std::is_same<char, char_type>::value,
- "incompatible string types");
- sstring.value = val;
- }
- value(const unsigned char* val) {
- static_assert(std::is_same<char, char_type>::value,
- "incompatible string types");
- ustring.value = val;
- }
+ value(long long val) : long_long_value(val) {}
+ value(unsigned long long val) : ulong_long_value(val) {}
+ value(double val) : double_value(val) {}
+ value(long double val) : long_double_value(val) {}
+ value(bool val) : bool_value(val) {}
+ value(char_type val) : char_value(val) {}
+ value(const char_type* val) { string.data = val; }
value(basic_string_view<char_type> val) {
- string.value = val.data();
+ string.data = val.data();
string.size = val.size();
}
- value(const void* val) { pointer = val; }
+ value(const void* val) : pointer(val) {}
- template <typename T> explicit value(const T& val) {
+ template <typename T> value(const T& val) {
custom.value = &val;
// Get the formatter type through the context to allow different contexts
// have different extension points, e.g. `formatter<T>` for `format` and
// `printf_formatter<T>` for `printf`.
- custom.format = &format_custom_arg<
- T, typename std::conditional<
- is_formattable<T, Context>::value,
- typename Context::template formatter_type<T>::type,
- internal::fallback_formatter<T, char_type>>::type>;
+ custom.format = format_custom_arg<
+ T, conditional_t<has_formatter<T, Context>::value,
+ typename Context::template formatter_type<T>,
+ fallback_formatter<T, char_type>>>;
}
- const named_arg_base<char_type>& as_named_arg() {
- return *static_cast<const named_arg_base<char_type>*>(pointer);
- }
+ value(const named_arg_base<char_type>& val) { named_arg = &val; }
private:
// Formats an argument of a custom type, such as a user-defined class.
@@ -752,148 +733,108 @@ template <typename Context> class value {
}
};
-// Value initializer used to delay conversion to value and reduce memory churn.
-template <typename Context, typename T, type TYPE> struct init {
- T val;
- static const type type_tag = TYPE;
-
- FMT_CONSTEXPR init(const T& v) : val(v) {}
- FMT_CONSTEXPR operator value<Context>() const { return value<Context>(val); }
-};
-
template <typename Context, typename T>
FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value);
-#define FMT_MAKE_VALUE(TAG, ArgType, ValueType) \
- template <typename C> \
- FMT_CONSTEXPR init<C, ValueType, TAG> make_value(ArgType val) { \
- return static_cast<ValueType>(val); \
- }
-
-#define FMT_MAKE_VALUE_SAME(TAG, Type) \
- template <typename C> \
- FMT_CONSTEXPR init<C, Type, TAG> make_value(Type val) { \
- return val; \
- }
-
-FMT_MAKE_VALUE(bool_type, bool, int)
-FMT_MAKE_VALUE(int_type, short, int)
-FMT_MAKE_VALUE(uint_type, unsigned short, unsigned)
-FMT_MAKE_VALUE_SAME(int_type, int)
-FMT_MAKE_VALUE_SAME(uint_type, unsigned)
-
// To minimize the number of types we need to deal with, long is translated
// either to int or to long long depending on its size.
-typedef std::conditional<sizeof(long) == sizeof(int), int, long long>::type
- long_type;
-FMT_MAKE_VALUE((sizeof(long) == sizeof(int) ? int_type : long_long_type), long,
- long_type)
-typedef std::conditional<sizeof(unsigned long) == sizeof(unsigned), unsigned,
- unsigned long long>::type ulong_type;
-FMT_MAKE_VALUE((sizeof(unsigned long) == sizeof(unsigned) ? uint_type
- : ulong_long_type),
- unsigned long, ulong_type)
-
-FMT_MAKE_VALUE_SAME(long_long_type, long long)
-FMT_MAKE_VALUE_SAME(ulong_long_type, unsigned long long)
-FMT_MAKE_VALUE(int_type, signed char, int)
-FMT_MAKE_VALUE(uint_type, unsigned char, unsigned)
-
-// This doesn't use FMT_MAKE_VALUE because of ambiguity in gcc 4.4.
-template <typename C, typename Char,
- FMT_ENABLE_IF(std::is_same<typename C::char_type, Char>::value)>
-FMT_CONSTEXPR init<C, int, char_type> make_value(Char val) {
- return val;
-}
-
-template <typename C,
- FMT_ENABLE_IF(!std::is_same<typename C::char_type, char>::value)>
-FMT_CONSTEXPR init<C, int, char_type> make_value(char val) {
- return val;
-}
-
-FMT_MAKE_VALUE(double_type, float, double)
-FMT_MAKE_VALUE_SAME(double_type, double)
-FMT_MAKE_VALUE_SAME(long_double_type, long double)
-
-// Formatting of wide strings into a narrow buffer and multibyte strings
-// into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606).
-FMT_MAKE_VALUE(cstring_type, typename C::char_type*,
- const typename C::char_type*)
-FMT_MAKE_VALUE(cstring_type, const typename C::char_type*,
- const typename C::char_type*)
-
-FMT_MAKE_VALUE(cstring_type, signed char*, const signed char*)
-FMT_MAKE_VALUE_SAME(cstring_type, const signed char*)
-FMT_MAKE_VALUE(cstring_type, unsigned char*, const unsigned char*)
-FMT_MAKE_VALUE_SAME(cstring_type, const unsigned char*)
-FMT_MAKE_VALUE_SAME(string_type, basic_string_view<typename C::char_type>)
-FMT_MAKE_VALUE(string_type,
- typename basic_string_view<typename C::char_type>::type,
- basic_string_view<typename C::char_type>)
-FMT_MAKE_VALUE(string_type, const std::basic_string<typename C::char_type>&,
- basic_string_view<typename C::char_type>)
-FMT_MAKE_VALUE(pointer_type, void*, const void*)
-FMT_MAKE_VALUE_SAME(pointer_type, const void*)
-
-#if FMT_USE_NULLPTR
-FMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void*)
-#endif
-
-// Formatting of arbitrary pointers is disallowed. If you want to output a
-// pointer cast it to "void *" or "const void *". In particular, this forbids
-// formatting of "[const] volatile char *" which is printed as bool by
-// iostreams.
-template <typename C, typename T,
- FMT_ENABLE_IF(!std::is_same<T, typename C::char_type>::value)>
-void make_value(const T*) {
- static_assert(!sizeof(T), "formatting of non-void pointers is disallowed");
-}
+enum { long_short = sizeof(long) == sizeof(int) };
+using long_type = conditional_t<long_short, int, long long>;
+using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
+
+// Maps formatting arguments to core types.
+template <typename Context> struct arg_mapper {
+ using char_type = typename Context::char_type;
+
+ FMT_CONSTEXPR int map(signed char val) { return val; }
+ FMT_CONSTEXPR unsigned map(unsigned char val) { return val; }
+ FMT_CONSTEXPR int map(short val) { return val; }
+ FMT_CONSTEXPR unsigned map(unsigned short val) { return val; }
+ FMT_CONSTEXPR int map(int val) { return val; }
+ FMT_CONSTEXPR unsigned map(unsigned val) { return val; }
+ FMT_CONSTEXPR long_type map(long val) { return val; }
+ FMT_CONSTEXPR ulong_type map(unsigned long val) { return val; }
+ FMT_CONSTEXPR long long map(long long val) { return val; }
+ FMT_CONSTEXPR unsigned long long map(unsigned long long val) { return val; }
+ FMT_CONSTEXPR bool map(bool val) { return val; }
+
+ template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
+ FMT_CONSTEXPR char_type map(T val) {
+ static_assert(
+ std::is_same<T, char>::value || std::is_same<T, char_type>::value,
+ "mixing character types is disallowed");
+ return val;
+ }
-template <typename C, typename T,
- FMT_ENABLE_IF(convert_to_int<T, typename C::char_type>::value&&
- std::is_enum<T>::value)>
-inline init<C, int, int_type> make_value(const T& val) {
- return static_cast<int>(val);
-}
+ FMT_CONSTEXPR double map(float val) { return static_cast<double>(val); }
+ FMT_CONSTEXPR double map(double val) { return val; }
+ FMT_CONSTEXPR long double map(long double val) { return val; }
+
+ FMT_CONSTEXPR const char_type* map(char_type* val) { return val; }
+ FMT_CONSTEXPR const char_type* map(const char_type* val) { return val; }
+ template <typename T, FMT_ENABLE_IF(is_string<T>::value)>
+ FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
+ static_assert(std::is_same<char_type, char_t<T>>::value,
+ "mixing character types is disallowed");
+ return to_string_view(val);
+ }
+ template <typename T,
+ FMT_ENABLE_IF(
+ std::is_constructible<basic_string_view<char_type>, T>::value &&
+ !is_string<T>::value)>
+ FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
+ return basic_string_view<char_type>(val);
+ }
+ FMT_CONSTEXPR const char* map(const signed char* val) {
+ static_assert(std::is_same<char_type, char>::value, "invalid string type");
+ return reinterpret_cast<const char*>(val);
+ }
+ FMT_CONSTEXPR const char* map(const unsigned char* val) {
+ static_assert(std::is_same<char_type, char>::value, "invalid string type");
+ return reinterpret_cast<const char*>(val);
+ }
-template <typename C, typename T, typename Char = typename C::char_type,
- FMT_ENABLE_IF(is_constructible<basic_string_view<Char>, T>::value &&
- !internal::is_string<T>::value)>
-inline init<C, basic_string_view<Char>, string_type> make_value(const T& val) {
- return basic_string_view<Char>(val);
-}
+ FMT_CONSTEXPR const void* map(void* val) { return val; }
+ FMT_CONSTEXPR const void* map(const void* val) { return val; }
+ FMT_CONSTEXPR const void* map(std::nullptr_t val) { return val; }
+ template <typename T> FMT_CONSTEXPR int map(const T*) {
+ // Formatting of arbitrary pointers is disallowed. If you want to output
+ // a pointer cast it to "void *" or "const void *". In particular, this
+ // forbids formatting of "[const] volatile char *" which is printed as bool
+ // by iostreams.
+ static_assert(!sizeof(T), "formatting of non-void pointers is disallowed");
+ return 0;
+ }
-// Implicit conversion to std::string is not handled here because it's
-// unsafe: https://github.com/fmtlib/fmt/issues/729
-template <
- typename C, typename T, typename Char = typename C::char_type,
- FMT_ENABLE_IF(!convert_to_int<T, Char>::value &&
- !std::is_same<T, Char>::value &&
- !std::is_convertible<T, basic_string_view<Char>>::value &&
- !is_constructible<basic_string_view<Char>, T>::value &&
- !internal::is_string<T>::value)>
-inline init<C, const T&, custom_type> make_value(const T& val) {
- return val;
-}
+ template <typename T,
+ FMT_ENABLE_IF(std::is_enum<T>::value &&
+ !has_formatter<T, Context>::value &&
+ !has_fallback_formatter<T, Context>::value)>
+ FMT_CONSTEXPR int map(const T& val) {
+ return static_cast<int>(val);
+ }
+ template <typename T,
+ FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value &&
+ (has_formatter<T, Context>::value ||
+ has_fallback_formatter<T, Context>::value))>
+ FMT_CONSTEXPR const T& map(const T& val) {
+ return val;
+ }
-template <typename C, typename T>
-init<C, const void*, named_arg_type> make_value(
- const named_arg<T, typename C::char_type>& val) {
- basic_format_arg<C> arg = make_arg<C>(val.value);
- std::memcpy(val.data, &arg, sizeof(arg));
- return static_cast<const void*>(&val);
-}
+ template <typename T>
+ FMT_CONSTEXPR const named_arg_base<char_type>& map(
+ const named_arg<T, char_type>& val) {
+ auto arg = make_arg<Context>(val.value);
+ std::memcpy(val.data, &arg, sizeof(arg));
+ return val;
+ }
+};
-template <typename C, typename S, FMT_ENABLE_IF(internal::is_string<S>::value)>
-FMT_CONSTEXPR11 init<C, basic_string_view<typename C::char_type>, string_type>
-make_value(const S& val) {
- // Handle adapted strings.
- static_assert(std::is_same<typename C::char_type,
- typename internal::char_t<S>::type>::value,
- "mismatch between char-types of context and argument");
- return to_string_view(val);
-}
+// A type constant after applying arg_mapper<Context>.
+template <typename T, typename Context>
+using mapped_type_constant =
+ type_constant<decltype(arg_mapper<Context>().map(std::declval<T>())),
+ typename Context::char_type>;
// Maximum number of arguments with packed types.
enum { max_packed_args = 15 };
@@ -914,13 +855,14 @@ template <typename Context> class basic_format_arg {
const T& value);
template <typename Visitor, typename Ctx>
- friend FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
- visit_format_arg(Visitor&& vis, const basic_format_arg<Ctx>& arg);
+ friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
+ const basic_format_arg<Ctx>& arg)
+ -> decltype(vis(0));
friend class basic_format_args<Context>;
friend class internal::arg_map<Context>;
- typedef typename Context::char_type char_type;
+ using char_type = typename Context::char_type;
public:
class handle {
@@ -937,7 +879,7 @@ template <typename Context> class basic_format_arg {
FMT_CONSTEXPR basic_format_arg() : type_(internal::none_type) {}
- FMT_CONSTEXPR FMT_EXPLICIT operator bool() const FMT_NOEXCEPT {
+ FMT_CONSTEXPR explicit operator bool() const FMT_NOEXCEPT {
return type_ != internal::none_type;
}
@@ -947,8 +889,6 @@ template <typename Context> class basic_format_arg {
bool is_arithmetic() const { return internal::is_arithmetic(type_); }
};
-struct monostate {};
-
/**
\rst
Visits an argument dispatching to the appropriate visit method based on
@@ -957,9 +897,10 @@ struct monostate {};
\endrst
*/
template <typename Visitor, typename Context>
-FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type visit_format_arg(
- Visitor&& vis, const basic_format_arg<Context>& arg) {
- typedef typename Context::char_type char_type;
+FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
+ const basic_format_arg<Context>& arg)
+ -> decltype(vis(0)) {
+ using char_type = typename Context::char_type;
switch (arg.type_) {
case internal::none_type:
break;
@@ -975,17 +916,17 @@ FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type visit_format_arg(
case internal::ulong_long_type:
return vis(arg.value_.ulong_long_value);
case internal::bool_type:
- return vis(arg.value_.int_value != 0);
+ return vis(arg.value_.bool_value);
case internal::char_type:
- return vis(static_cast<char_type>(arg.value_.int_value));
+ return vis(arg.value_.char_value);
case internal::double_type:
return vis(arg.value_.double_value);
case internal::long_double_type:
return vis(arg.value_.long_double_value);
case internal::cstring_type:
- return vis(arg.value_.string.value);
+ return vis(arg.value_.string.data);
case internal::string_type:
- return vis(basic_string_view<char_type>(arg.value_.string.value,
+ return vis(basic_string_view<char_type>(arg.value_.string.data,
arg.value_.string.size));
case internal::pointer_type:
return vis(arg.value_.pointer);
@@ -996,8 +937,9 @@ FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type visit_format_arg(
}
template <typename Visitor, typename Context>
-FMT_DEPRECATED FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
-visit(Visitor&& vis, const basic_format_arg<Context>& arg) {
+FMT_DEPRECATED FMT_CONSTEXPR auto visit(Visitor&& vis,
+ const basic_format_arg<Context>& arg)
+ -> decltype(vis(0)) {
return visit_format_arg(std::forward<Visitor>(vis), arg);
}
@@ -1008,7 +950,7 @@ template <typename Context> class arg_map {
arg_map(const arg_map&) = delete;
void operator=(const arg_map&) = delete;
- typedef typename Context::char_type char_type;
+ using char_type = typename Context::char_type;
struct entry {
basic_string_view<char_type> name;
@@ -1019,13 +961,13 @@ template <typename Context> class arg_map {
unsigned size_;
void push_back(value<Context> val) {
- const internal::named_arg_base<char_type>& named = val.as_named_arg();
- map_[size_] = entry{named.name, named.template deserialize<Context>()};
+ const auto& named = *val.named_arg;
+ map_[size_] = {named.name, named.template deserialize<Context>()};
++size_;
}
public:
- arg_map() : map_(FMT_NULL), size_(0) {}
+ arg_map() : map_(nullptr), size_(0) {}
void init(const basic_format_args<Context>& args);
~arg_map() { delete[] map_; }
@@ -1042,42 +984,34 @@ template <typename Context> class arg_map {
class locale_ref {
private:
const void* locale_; // A type-erased pointer to std::locale.
- friend class locale;
public:
- locale_ref() : locale_(FMT_NULL) {}
+ locale_ref() : locale_(nullptr) {}
template <typename Locale> explicit locale_ref(const Locale& loc);
template <typename Locale> Locale get() const;
};
-template <typename Context, typename T> struct get_type {
- typedef decltype(
- make_value<Context>(declval<typename std::decay<T>::type&>())) value_type;
- static const type value = value_type::type_tag;
-};
-
-template <typename Context> FMT_CONSTEXPR11 unsigned long long get_types() {
- return 0;
-}
+template <typename> constexpr unsigned long long encode_types() { return 0; }
template <typename Context, typename Arg, typename... Args>
-FMT_CONSTEXPR11 unsigned long long get_types() {
- return get_type<Context, Arg>::value | (get_types<Context, Args...>() << 4);
+constexpr unsigned long long encode_types() {
+ return mapped_type_constant<Arg, Context>::value |
+ (encode_types<Context, Args...>() << 4);
}
template <typename Context, typename T>
FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value) {
basic_format_arg<Context> arg;
- arg.type_ = get_type<Context, T>::value;
- arg.value_ = make_value<Context>(value);
+ arg.type_ = mapped_type_constant<T, Context>::value;
+ arg.value_ = arg_mapper<Context>().map(value);
return arg;
}
template <bool IS_PACKED, typename Context, typename T,
FMT_ENABLE_IF(IS_PACKED)>
-inline value<Context> make_arg(const T& value) {
- return make_value<Context>(value);
+inline value<Context> make_arg(const T& val) {
+ return arg_mapper<Context>().map(val);
}
template <bool IS_PACKED, typename Context, typename T,
@@ -1091,7 +1025,7 @@ inline basic_format_arg<Context> make_arg(const T& value) {
template <typename OutputIt, typename Char> class basic_format_context {
public:
/** The character type for the output. */
- typedef Char char_type;
+ using char_type = Char;
private:
OutputIt out_;
@@ -1103,13 +1037,9 @@ template <typename OutputIt, typename Char> class basic_format_context {
void operator=(const basic_format_context&) = delete;
public:
- typedef OutputIt iterator;
- typedef basic_format_arg<basic_format_context> format_arg;
-
- // using formatter_type = formatter<T, char_type>;
- template <typename T> struct formatter_type {
- typedef formatter<T, char_type> type;
- };
+ using iterator = OutputIt;
+ using format_arg = basic_format_arg<basic_format_context>;
+ template <typename T> using formatter_type = formatter<T, char_type>;
/**
Constructs a ``basic_format_context`` object. References to the arguments are
@@ -1139,13 +1069,12 @@ template <typename OutputIt, typename Char> class basic_format_context {
internal::locale_ref locale() { return loc_; }
};
-template <typename Char> struct buffer_context {
- typedef basic_format_context<
- std::back_insert_iterator<internal::basic_buffer<Char>>, Char>
- type;
-};
-typedef buffer_context<char>::type format_context;
-typedef buffer_context<wchar_t>::type wformat_context;
+template <typename Char>
+using buffer_context =
+ basic_format_context<std::back_insert_iterator<internal::buffer<Char>>,
+ Char>;
+using format_context = buffer_context<char>;
+using wformat_context = buffer_context<wchar_t>;
/**
\rst
@@ -1156,53 +1085,27 @@ typedef buffer_context<wchar_t>::type wformat_context;
*/
template <typename Context, typename... Args> class format_arg_store {
private:
- static const size_t NUM_ARGS = sizeof...(Args);
-
- // Packed is a macro on MinGW so use IS_PACKED instead.
- static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args;
+ static const size_t num_args = sizeof...(Args);
+ static const bool is_packed = num_args < internal::max_packed_args;
- typedef typename std::conditional<IS_PACKED, internal::value<Context>,
- basic_format_arg<Context>>::type value_type;
+ using value_type = conditional_t<is_packed, internal::value<Context>,
+ basic_format_arg<Context>>;
// If the arguments are not packed, add one more element to mark the end.
- static const size_t DATA_SIZE =
- NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1);
- value_type data_[DATA_SIZE];
+ value_type data_[num_args + (!is_packed || num_args == 0 ? 1 : 0)];
friend class basic_format_args<Context>;
- static FMT_CONSTEXPR11 unsigned long long get_types() {
- return IS_PACKED ? internal::get_types<Context, Args...>()
- : internal::is_unpacked_bit | NUM_ARGS;
- }
-
public:
-#if FMT_USE_CONSTEXPR11
- static FMT_CONSTEXPR11 unsigned long long TYPES = get_types();
-#else
- static const unsigned long long TYPES;
-#endif
+ static constexpr unsigned long long types =
+ is_packed ? internal::encode_types<Context, Args...>()
+ : internal::is_unpacked_bit | num_args;
+ FMT_DEPRECATED static constexpr unsigned long long TYPES = types;
-#if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 405) || \
- (FMT_MSC_VER && FMT_MSC_VER <= 1800)
- // Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013.
- format_arg_store(const Args&... args) {
- value_type init[DATA_SIZE] = {
- internal::make_arg<IS_PACKED, Context>(args)...};
- std::memcpy(data_, init, sizeof(init));
- }
-#else
format_arg_store(const Args&... args)
- : data_{internal::make_arg<IS_PACKED, Context>(args)...} {}
-#endif
+ : data_{internal::make_arg<is_packed, Context>(args)...} {}
};
-#if !FMT_USE_CONSTEXPR11
-template <typename Context, typename... Args>
-const unsigned long long format_arg_store<Context, Args...>::TYPES =
- get_types();
-#endif
-
/**
\rst
Constructs an `~fmt::format_arg_store` object that contains references to
@@ -1220,8 +1123,8 @@ inline format_arg_store<Context, Args...> make_format_args(
/** Formatting arguments. */
template <typename Context> class basic_format_args {
public:
- typedef unsigned size_type;
- typedef basic_format_arg<Context> format_arg;
+ using size_type = unsigned;
+ using format_arg = basic_format_arg<Context>;
private:
// To reduce compiled code size per formatting function call, types of first
@@ -1239,10 +1142,9 @@ template <typename Context> class basic_format_args {
bool is_packed() const { return (types_ & internal::is_unpacked_bit) == 0; }
- typename internal::type type(unsigned index) const {
+ internal::type type(unsigned index) const {
unsigned shift = index * 4;
- return static_cast<typename internal::type>((types_ & (0xfull << shift)) >>
- shift);
+ return static_cast<internal::type>((types_ & (0xfull << shift)) >> shift);
}
friend class internal::arg_map<Context>;
@@ -1275,7 +1177,7 @@ template <typename Context> class basic_format_args {
*/
template <typename... Args>
basic_format_args(const format_arg_store<Context, Args...>& store)
- : types_(static_cast<unsigned long long>(store.TYPES)) {
+ : types_(static_cast<unsigned long long>(store.types)) {
set_data(store.data_);
}
@@ -1293,7 +1195,7 @@ template <typename Context> class basic_format_args {
format_arg get(size_type index) const {
format_arg arg = do_get(index);
if (arg.type_ == internal::named_arg_type)
- arg = arg.value_.as_named_arg().template deserialize<Context>();
+ arg = arg.value_.named_arg->template deserialize<Context>();
return arg;
}
@@ -1305,43 +1207,39 @@ template <typename Context> class basic_format_args {
};
/** An alias to ``basic_format_args<context>``. */
-// It is a separate type rather than a typedef to make symbols readable.
+// It is a separate type rather than an alias to make symbols readable.
struct format_args : basic_format_args<format_context> {
template <typename... Args>
- format_args(Args&&... arg)
- : basic_format_args<format_context>(std::forward<Args>(arg)...) {}
+ format_args(Args&&... args)
+ : basic_format_args<format_context>(std::forward<Args>(args)...) {}
};
struct wformat_args : basic_format_args<wformat_context> {
template <typename... Args>
- wformat_args(Args&&... arg)
- : basic_format_args<wformat_context>(std::forward<Args>(arg)...) {}
+ wformat_args(Args&&... args)
+ : basic_format_args<wformat_context>(std::forward<Args>(args)...) {}
};
-#ifndef FMT_USE_ALIAS_TEMPLATES
-# define FMT_USE_ALIAS_TEMPLATES FMT_HAS_FEATURE(cxx_alias_templates)
-#endif
-#if FMT_USE_ALIAS_TEMPLATES
-/** String's character type. */
-template <typename S> using char_t = typename internal::char_t<S>::type;
-# define FMT_CHAR(S) fmt::char_t<S>
-#else
-# define FMT_CHAR(S) typename internal::char_t<S>::type
-#endif
+template <typename Container> struct is_contiguous : std::false_type {};
+
+template <typename Char>
+struct is_contiguous<std::basic_string<Char>> : std::true_type {};
+
+template <typename Char>
+struct is_contiguous<internal::buffer<Char>> : std::true_type {};
namespace internal {
-template <typename Context>
-FMT_CONSTEXPR typename Context::format_arg get_arg(Context& ctx, unsigned id) {
- auto arg = ctx.arg(id);
- if (!arg) ctx.on_error("argument index out of range");
- return arg;
-}
+
+template <typename OutputIt>
+struct is_contiguous_back_insert_iterator : std::false_type {};
+template <typename Container>
+struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
+ : is_contiguous<Container> {};
template <typename Char> struct named_arg_base {
basic_string_view<Char> name;
// Serialized value<context>.
- mutable char
- data[sizeof(basic_format_arg<typename buffer_context<Char>::type>)];
+ mutable char data[sizeof(basic_format_arg<buffer_context<Char>>)];
named_arg_base(basic_string_view<Char> nm) : name(nm) {}
@@ -1359,30 +1257,26 @@ template <typename T, typename Char> struct named_arg : named_arg_base<Char> {
: named_arg_base<Char>(name), value(val) {}
};
-template <typename... Args, typename S,
- FMT_ENABLE_IF(!is_compile_string<S>::value)>
+template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
inline void check_format_string(const S&) {}
-template <typename... Args, typename S,
- FMT_ENABLE_IF(is_compile_string<S>::value)>
+template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
void check_format_string(S);
-template <typename S, typename... Args,
- FMT_ENABLE_IF(internal::is_string<S>::value)>
-inline format_arg_store<typename buffer_context<FMT_CHAR(S)>::type, Args...>
-make_args_checked(const S& format_str, const Args&... args) {
- internal::check_format_string<Args...>(format_str);
+template <typename S, typename... Args, typename Char = char_t<S>>
+inline format_arg_store<buffer_context<Char>, Args...> make_args_checked(
+ const S& format_str, const Args&... args) {
+ check_format_string<Args...>(format_str);
return {args...};
}
template <typename Char>
-std::basic_string<Char> vformat(
- basic_string_view<Char> format_str,
- basic_format_args<typename buffer_context<Char>::type> args);
+std::basic_string<Char> vformat(basic_string_view<Char> format_str,
+ basic_format_args<buffer_context<Char>> args);
template <typename Char>
-typename buffer_context<Char>::type::iterator vformat_to(
- internal::basic_buffer<Char>& buf, basic_string_view<Char> format_str,
- basic_format_args<typename buffer_context<Char>::type> args);
+typename buffer_context<Char>::iterator vformat_to(
+ buffer<Char>& buf, basic_string_view<Char> format_str,
+ basic_format_args<buffer_context<Char>> args);
} // namespace internal
/**
@@ -1400,8 +1294,9 @@ typename buffer_context<Char>::type::iterator vformat_to(
fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
\endrst
*/
-template <typename S, typename T, FMT_ENABLE_IF(internal::is_string<S>::value)>
-inline internal::named_arg<T, FMT_CHAR(S)> arg(const S& name, const T& arg) {
+template <typename S, typename T, typename Char = char_t<S>>
+inline internal::named_arg<T, Char> arg(const S& name, const T& arg) {
+ static_assert(internal::is_string<S>::value, "");
return {name, arg};
}
@@ -1409,21 +1304,16 @@ inline internal::named_arg<T, FMT_CHAR(S)> arg(const S& name, const T& arg) {
template <typename S, typename T, typename Char>
void arg(S, internal::named_arg<T, Char>) = delete;
-template <typename Container> struct is_contiguous : std::false_type {};
-
-template <typename Char>
-struct is_contiguous<std::basic_string<Char>> : std::true_type {};
-
-template <typename Char>
-struct is_contiguous<internal::basic_buffer<Char>> : std::true_type {};
-
/** Formats a string and writes the output to ``out``. */
-template <typename Container, typename S>
-typename std::enable_if<is_contiguous<Container>::value,
- std::back_insert_iterator<Container>>::type
-vformat_to(std::back_insert_iterator<Container> out, const S& format_str,
- basic_format_args<typename buffer_context<FMT_CHAR(S)>::type> args) {
- internal::container_buffer<Container> buf(internal::get_container(out));
+// GCC 8 and earlier cannot handle std::back_insert_iterator<Container> with
+// vformat_to<ArgFormatter>(...) overload, so SFINAE on iterator type instead.
+template <typename OutputIt, typename S, typename Char = char_t<S>,
+ FMT_ENABLE_IF(
+ internal::is_contiguous_back_insert_iterator<OutputIt>::value)>
+OutputIt vformat_to(OutputIt out, const S& format_str,
+ basic_format_args<buffer_context<Char>> args) {
+ using container = remove_reference_t<decltype(internal::get_container(out))>;
+ internal::container_buffer<container> buf((internal::get_container(out)));
internal::vformat_to(buf, to_string_view(format_str), args);
return out;
}
@@ -1438,11 +1328,9 @@ inline std::back_insert_iterator<Container> format_to(
{internal::make_args_checked(format_str, args...)});
}
-template <typename S, typename Char = FMT_CHAR(S),
- FMT_ENABLE_IF(internal::is_string<S>::value)>
+template <typename S, typename Char = char_t<S>>
inline std::basic_string<Char> vformat(
- const S& format_str,
- basic_format_args<typename buffer_context<Char>::type> args) {
+ const S& format_str, basic_format_args<buffer_context<Char>> args) {
return internal::vformat(to_string_view(format_str), args);
}
@@ -1456,10 +1344,11 @@ inline std::basic_string<Char> vformat(
std::string message = fmt::format("The answer is {}", 42);
\endrst
*/
-template <typename S, typename... Args,
- FMT_ENABLE_IF(internal::is_string<S>::value)>
-inline std::basic_string<FMT_CHAR(S)> format(const S& format_str,
- const Args&... args) {
+// Pass char_t as a default template parameter instead of using
+// std::basic_string<char_t<S>> to reduce the symbol size.
+template <typename S, typename... Args, typename Char = char_t<S>>
+inline std::basic_string<Char> format(const S& format_str,
+ const Args&... args) {
return internal::vformat(to_string_view(format_str),
{internal::make_args_checked(format_str, args...)});
}
diff --git a/src/third_party/fmt/dist/include/fmt/format-inl.h b/src/third_party/fmt/dist/include/fmt/format-inl.h
index ad82d328679..cce1a34a426 100644
--- a/src/third_party/fmt/dist/include/fmt/format-inl.h
+++ b/src/third_party/fmt/dist/include/fmt/format-inl.h
@@ -63,8 +63,7 @@ inline fmt::internal::null<> strerror_s(char*, std::size_t, ...) {
}
FMT_BEGIN_NAMESPACE
-
-namespace {
+namespace internal {
#ifndef _MSC_VER
# define FMT_SNPRINTF snprintf
@@ -79,13 +78,7 @@ inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) {
# define FMT_SNPRINTF fmt_snprintf
#endif // _MSC_VER
-#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
-# define FMT_SWPRINTF snwprintf
-#else
-# define FMT_SWPRINTF swprintf
-#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
-
-typedef void (*FormatFunc)(internal::buffer&, int, string_view);
+typedef void (*FormatFunc)(internal::buffer<char>&, int, string_view);
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
@@ -96,9 +89,9 @@ typedef void (*FormatFunc)(internal::buffer&, int, string_view);
// ERANGE - buffer is not large enough to store the error message
// other - failure
// Buffer should be at least of size 1.
-int safe_strerror(int error_code, char*& buffer,
- std::size_t buffer_size) FMT_NOEXCEPT {
- FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
+FMT_FUNC int safe_strerror(int error_code, char*& buffer,
+ std::size_t buffer_size) FMT_NOEXCEPT {
+ FMT_ASSERT(buffer != nullptr && buffer_size != 0, "invalid buffer");
class dispatcher {
private:
@@ -154,8 +147,8 @@ int safe_strerror(int error_code, char*& buffer,
return dispatcher(error_code, buffer, buffer_size).run();
}
-void format_error_code(internal::buffer& out, int error_code,
- string_view message) FMT_NOEXCEPT {
+FMT_FUNC void format_error_code(internal::buffer<char>& out, int error_code,
+ string_view message) FMT_NOEXCEPT {
// Report error code making sure that the output fits into
// inline_buffer_size to avoid dynamic memory allocation and potential
// bad_alloc.
@@ -182,15 +175,16 @@ void format_error_code(internal::buffer& out, int error_code,
}
// try an fwrite, FMT_THROW on failure
-void fwrite_fully(const void* ptr, size_t size, size_t count, FILE* stream) {
+FMT_FUNC void fwrite_fully(const void* ptr, size_t size, size_t count,
+ FILE* stream) {
size_t written = std::fwrite(ptr, size, count, stream);
if (written < count) {
FMT_THROW(system_error(errno, "cannot write to file"));
}
}
-void report_error(FormatFunc func, int error_code,
- string_view message) FMT_NOEXCEPT {
+FMT_FUNC void report_error(FormatFunc func, int error_code,
+ string_view message) FMT_NOEXCEPT {
memory_buffer full_message;
func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory
@@ -198,16 +192,7 @@ void report_error(FormatFunc func, int error_code,
fwrite_fully(full_message.data(), 1, full_message.size(), stderr);
std::fputc('\n', stderr);
}
-} // namespace
-
-FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
- const char8_t* data = s.data();
- size_t num_code_points = 0;
- for (size_t i = 0, size = s.size(); i != size; ++i) {
- if ((data[i] & 0xc0) != 0x80) ++num_code_points;
- }
- return num_code_points;
-}
+} // namespace internal
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
namespace internal {
@@ -223,7 +208,7 @@ template <typename Locale> Locale locale_ref::get() const {
}
template <typename Char> FMT_FUNC Char thousands_sep_impl(locale_ref loc) {
- return std::use_facet<std::numpunct<Char> >(loc.get<std::locale>())
+ return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
.thousands_sep();
}
} // namespace internal
@@ -234,6 +219,9 @@ FMT_FUNC Char internal::thousands_sep_impl(locale_ref) {
}
#endif
+FMT_API FMT_FUNC format_error::~format_error() FMT_NOEXCEPT {}
+FMT_API FMT_FUNC system_error::~system_error() FMT_NOEXCEPT {}
+
FMT_FUNC void system_error::init(int err_code, string_view format_str,
format_args args) {
error_code_ = err_code;
@@ -244,20 +232,22 @@ FMT_FUNC void system_error::init(int err_code, string_view format_str,
}
namespace internal {
-template <typename T>
-int char_traits<char>::format_float(char* buf, std::size_t size,
- const char* format, int precision,
- T value) {
- return precision < 0 ? FMT_SNPRINTF(buf, size, format, value)
- : FMT_SNPRINTF(buf, size, format, precision, value);
+
+template <> FMT_FUNC int count_digits<4>(internal::fallback_uintptr n) {
+ // Assume little endian; pointer formatting is implementation-defined anyway.
+ int i = static_cast<int>(sizeof(void*)) - 1;
+ while (i > 0 && n.value[i] == 0) --i;
+ auto char_digits = std::numeric_limits<unsigned char>::digits / 4;
+ return i >= 0 ? i * char_digits + count_digits<4, unsigned>(n.value[i]) : 1;
}
template <typename T>
-int char_traits<wchar_t>::format_float(wchar_t* buf, std::size_t size,
- const wchar_t* format, int precision,
- T value) {
- return precision < 0 ? FMT_SWPRINTF(buf, size, format, value)
- : FMT_SWPRINTF(buf, size, format, precision, value);
+int format_float(char* buf, std::size_t size, const char* format, int precision,
+ T value) {
+ // Suppress the warning about nonliteral format string.
+ auto snprintf_ptr = FMT_SNPRINTF;
+ return precision < 0 ? snprintf_ptr(buf, size, format, value)
+ : snprintf_ptr(buf, size, format, precision, value);
}
template <typename T>
@@ -268,6 +258,9 @@ const char basic_data<T>::DIGITS[] =
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
+template <typename T>
+const char basic_data<T>::HEX_DIGITS[] = "0123456789abcdef";
+
#define FMT_POWERS_OF_10(factor) \
factor * 10, factor * 100, factor * 1000, factor * 10000, factor * 100000, \
factor * 1000000, factor * 10000000, factor * 100000000, \
@@ -428,6 +421,13 @@ inline fp operator-(fp x, fp y) {
// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be
// normalized.
FMT_FUNC fp operator*(fp x, fp y) {
+ int exp = x.e + y.e + 64;
+#if FMT_USE_INT128
+ auto product = static_cast<__uint128_t>(x.f) * y.f;
+ auto f = static_cast<uint64_t>(product >> 64);
+ if ((static_cast<uint64_t>(product) & (1ULL << 63)) != 0) ++f;
+ return fp(f, exp);
+#else
// Multiply 32-bit parts of significands.
uint64_t mask = (1ULL << 32) - 1;
uint64_t a = x.f >> 32, b = x.f & mask;
@@ -435,7 +435,8 @@ FMT_FUNC fp operator*(fp x, fp y) {
uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
// Compute mid 64-bit of result and round.
uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
- return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
+ return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), exp);
+#endif
}
// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
@@ -483,10 +484,12 @@ enum result {
};
}
-// Generates output using Grisu2 digit-gen algorithm.
+// Generates output using the Grisu digit-gen algorithm.
+// error: the size of the region (lower, upper) outside of which numbers
+// definitely do not round to value (Delta in Grisu3).
template <typename Handler>
-digits::result grisu2_gen_digits(fp value, uint64_t error, int& exp,
- Handler& handler) {
+digits::result grisu_gen_digits(fp value, uint64_t error, int& exp,
+ Handler& handler) {
fp one(1ull << -value.e, value.e);
// The integral part of scaled value (p1 in Grisu) = value / one. It cannot be
// zero because it contains a product of two 64-bit numbers with MSB set (due
@@ -599,7 +602,7 @@ struct fixed_handler {
uint64_t error, int, bool integral) {
FMT_ASSERT(remainder < divisor, "");
buf[size++] = digit;
- if (size != precision) return digits::more;
+ if (size < precision) return digits::more;
if (!integral) {
// Check if error * 2 < divisor with overflow prevention.
// The check is not needed for the integral part because error = 1
@@ -624,34 +627,58 @@ struct fixed_handler {
};
// The shortest representation digit handler.
-struct shortest_handler {
+template <int GRISU_VERSION> struct grisu_shortest_handler {
char* buf;
int size;
- fp diff; // wp_w in Grisu.
+ // Distance between scaled value and upper bound (wp_W in Grisu3).
+ uint64_t diff;
digits::result on_start(uint64_t, uint64_t, uint64_t, int&) {
return digits::more;
}
- digits::result on_digit(char digit, uint64_t divisor, uint64_t remainder,
- uint64_t error, int exp, bool integral) {
- buf[size++] = digit;
- if (remainder > error) return digits::more;
- uint64_t d = integral ? diff.f : diff.f * data::POWERS_OF_10_64[-exp];
+
+ // Decrement the generated number approaching value from above.
+ void round(uint64_t d, uint64_t divisor, uint64_t& remainder,
+ uint64_t error) {
while (
remainder < d && error - remainder >= divisor &&
- (remainder + divisor < d || d - remainder > remainder + divisor - d)) {
+ (remainder + divisor < d || d - remainder >= remainder + divisor - d)) {
--buf[size - 1];
remainder += divisor;
}
- return digits::done;
+ }
+
+ // Implements Grisu's round_weed.
+ digits::result on_digit(char digit, uint64_t divisor, uint64_t remainder,
+ uint64_t error, int exp, bool integral) {
+ buf[size++] = digit;
+ if (remainder >= error) return digits::more;
+ if (GRISU_VERSION != 3) {
+ uint64_t d = integral ? diff : diff * data::POWERS_OF_10_64[-exp];
+ round(d, divisor, remainder, error);
+ return digits::done;
+ }
+ uint64_t unit = integral ? 1 : data::POWERS_OF_10_64[-exp];
+ uint64_t up = (diff - 1) * unit; // wp_Wup
+ round(up, divisor, remainder, error);
+ uint64_t down = (diff + 1) * unit; // wp_Wdown
+ if (remainder < down && error - remainder >= divisor &&
+ (remainder + divisor < down ||
+ down - remainder > remainder + divisor - down)) {
+ return digits::error;
+ }
+ return 2 * unit <= remainder && remainder <= error - 4 * unit
+ ? digits::done
+ : digits::error;
}
};
-template <typename Double, typename std::enable_if<
- sizeof(Double) == sizeof(uint64_t), int>::type>
-FMT_FUNC bool grisu2_format(Double value, buffer& buf, int precision,
- bool fixed, int& exp) {
+template <typename Double,
+ enable_if_t<(sizeof(Double) == sizeof(uint64_t)), int>>
+FMT_API bool grisu_format(Double value, buffer<char>& buf, int precision,
+ unsigned options, int& exp) {
FMT_ASSERT(value >= 0, "value is negative");
+ bool fixed = (options & grisu_options::fixed) != 0;
if (value <= 0) { // <= instead of == to silence a warning.
if (precision < 0 || !fixed) {
exp = 0;
@@ -674,7 +701,7 @@ FMT_FUNC bool grisu2_format(Double value, buffer& buf, int precision,
min_exp - (fp_value.e + fp::significand_size), cached_exp10);
fp_value = fp_value * cached_pow;
fixed_handler handler{buf.data(), 0, precision, -cached_exp10, fixed};
- if (grisu2_gen_digits(fp_value, 1, exp, handler) == digits::error)
+ if (grisu_gen_digits(fp_value, 1, exp, handler) == digits::error)
return false;
buf.resize(to_unsigned(handler.size));
} else {
@@ -684,24 +711,36 @@ FMT_FUNC bool grisu2_format(Double value, buffer& buf, int precision,
// the exponent in the range [min_exp, -32].
auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
min_exp - (upper.e + fp::significand_size), cached_exp10);
- upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
- --upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
- assert(min_exp <= upper.e && upper.e <= -32);
fp_value.normalize();
fp_value = fp_value * cached_pow;
lower = lower * cached_pow; // \tilde{M}^- in Grisu.
- ++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
- shortest_handler handler{buf.data(), 0, upper - fp_value};
- auto result = grisu2_gen_digits(upper, upper.f - lower.f, exp, handler);
+ upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
+ assert(min_exp <= upper.e && upper.e <= -32);
+ auto result = digits::result();
+ int size = 0;
+ if ((options & grisu_options::grisu3) != 0) {
+ --lower.f; // \tilde{M}^- - 1 ulp -> M^-_{\downarrow}.
+ ++upper.f; // \tilde{M}^+ + 1 ulp -> M^+_{\uparrow}.
+ // Numbers outside of (lower, upper) definitely do not round to value.
+ grisu_shortest_handler<3> handler{buf.data(), 0, (upper - fp_value).f};
+ result = grisu_gen_digits(upper, upper.f - lower.f, exp, handler);
+ size = handler.size;
+ } else {
+ ++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
+ --upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
+ grisu_shortest_handler<2> handler{buf.data(), 0, (upper - fp_value).f};
+ result = grisu_gen_digits(upper, upper.f - lower.f, exp, handler);
+ size = handler.size;
+ }
if (result == digits::error) return false;
- buf.resize(to_unsigned(handler.size));
+ buf.resize(to_unsigned(size));
}
exp -= cached_exp10;
return true;
}
template <typename Double>
-void sprintf_format(Double value, internal::buffer& buf,
+void sprintf_format(Double value, internal::buffer<char>& 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");
@@ -734,32 +773,33 @@ void sprintf_format(Double value, internal::buffer& buf,
*format_ptr = '\0';
// Format using snprintf.
- char* start = FMT_NULL;
+ char* start = nullptr;
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);
+ int result =
+ format_float(start, buffer_size, format, spec.precision, value);
if (result >= 0) {
unsigned n = internal::to_unsigned(result);
if (n < buf.capacity()) {
// Find the decimal point.
auto p = buf.data(), end = p + n;
if (*p == '+' || *p == '-') ++p;
- if (spec.type == 'a' || spec.type == 'A') p += 2; // Skip "0x".
- while (p < end && *p >= '0' && *p <= '9') ++p;
- if (p < end && *p != 'e' && *p != 'E') {
- if (*p != '.') *p = '.';
- if (!spec.type) {
- // Keep only one trailing zero after the decimal point.
- ++p;
- if (*p == '0') ++p;
- while (p != end && *p >= '1' && *p <= '9') ++p;
- char* where = p;
- while (p != end && *p == '0') ++p;
- if (p == end || *p < '0' || *p > '9') {
- if (p != end) std::memmove(where, p, to_unsigned(end - p));
- n -= static_cast<unsigned>(p - where);
+ if (spec.type != 'a' && spec.type != 'A') {
+ while (p < end && *p >= '0' && *p <= '9') ++p;
+ if (p < end && *p != 'e' && *p != 'E') {
+ if (*p != '.') *p = '.';
+ if (!spec.type) {
+ // Keep only one trailing zero after the decimal point.
+ ++p;
+ if (*p == '0') ++p;
+ while (p != end && *p >= '1' && *p <= '9') ++p;
+ char* where = p;
+ while (p != end && *p == '0') ++p;
+ if (p == end || *p < '0' || *p > '9') {
+ if (p != end) std::memmove(where, p, to_unsigned(end - p));
+ n -= static_cast<unsigned>(p - where);
+ }
}
}
}
@@ -791,7 +831,7 @@ FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
}
int length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(),
- s_size, FMT_NULL, 0);
+ s_size, nullptr, 0);
if (length == 0) FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
buffer_.resize(length + 1);
length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size,
@@ -817,12 +857,12 @@ FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
return 0;
}
- int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0,
- FMT_NULL, FMT_NULL);
+ int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, nullptr, 0,
+ nullptr, nullptr);
if (length == 0) return GetLastError();
buffer_.resize(length + 1);
length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0],
- length, FMT_NULL, FMT_NULL);
+ length, nullptr, nullptr);
if (length == 0) return GetLastError();
buffer_[length] = 0;
return 0;
@@ -837,7 +877,7 @@ FMT_FUNC void windows_error::init(int err_code, string_view format_str,
base = std::runtime_error(to_string(buffer));
}
-FMT_FUNC void internal::format_windows_error(internal::buffer& out,
+FMT_FUNC void internal::format_windows_error(internal::buffer<char>& out,
int error_code,
string_view message) FMT_NOEXCEPT {
FMT_TRY {
@@ -846,9 +886,9 @@ FMT_FUNC void internal::format_windows_error(internal::buffer& out,
for (;;) {
wchar_t* system_message = &buf[0];
int result = FormatMessageW(
- FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, FMT_NULL,
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message,
- static_cast<uint32_t>(buf.size()), FMT_NULL);
+ static_cast<uint32_t>(buf.size()), nullptr);
if (result != 0) {
utf16_to_utf8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
@@ -871,14 +911,15 @@ FMT_FUNC void internal::format_windows_error(internal::buffer& out,
#endif // FMT_USE_WINDOWS_H
-FMT_FUNC void format_system_error(internal::buffer& out, int error_code,
+FMT_FUNC void format_system_error(internal::buffer<char>& out, int error_code,
string_view message) FMT_NOEXCEPT {
FMT_TRY {
memory_buffer buf;
buf.resize(inline_buffer_size);
for (;;) {
char* system_message = &buf[0];
- int result = safe_strerror(error_code, system_message, buf.size());
+ int result =
+ internal::safe_strerror(error_code, system_message, buf.size());
if (result == 0) {
writer w(out);
w.write(message);
@@ -914,14 +955,14 @@ FMT_FUNC void report_windows_error(int error_code,
FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
memory_buffer buffer;
internal::vformat_to(buffer, format_str,
- basic_format_args<buffer_context<char>::type>(args));
- fwrite_fully(buffer.data(), 1, buffer.size(), f);
+ basic_format_args<buffer_context<char>>(args));
+ internal::fwrite_fully(buffer.data(), 1, buffer.size(), f);
}
FMT_FUNC void vprint(std::FILE* f, wstring_view format_str, wformat_args args) {
wmemory_buffer buffer;
internal::vformat_to(buffer, format_str, args);
- fwrite_fully(buffer.data(), sizeof(wchar_t), buffer.size(), f);
+ internal::fwrite_fully(buffer.data(), sizeof(wchar_t), buffer.size(), f);
}
FMT_FUNC void vprint(string_view format_str, format_args args) {
diff --git a/src/third_party/fmt/dist/include/fmt/format.h b/src/third_party/fmt/dist/include/fmt/format.h
index e13f498dc56..a931bdcd04e 100644
--- a/src/third_party/fmt/dist/include/fmt/format.h
+++ b/src/third_party/fmt/dist/include/fmt/format.h
@@ -28,15 +28,18 @@
#ifndef FMT_FORMAT_H_
#define FMT_FORMAT_H_
-#include <stdint.h>
#include <algorithm>
#include <cassert>
#include <cmath>
+#include <cstdint>
#include <cstring>
+#include <iterator>
#include <limits>
#include <memory>
#include <stdexcept>
+#include "core.h"
+
#ifdef __clang__
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
#else
@@ -57,58 +60,12 @@
# define FMT_CUDA_VERSION 0
#endif
-#include "core.h"
-
-#if FMT_GCC_VERSION >= 406 || FMT_CLANG_VERSION
-# pragma GCC diagnostic push
-
-// Disable warning about not handling all enums in switch statement even with
-// a default case
-# pragma GCC diagnostic ignored "-Wswitch-enum"
-
-// Disable the warning about declaration shadowing because it affects too
-// many valid cases.
-# pragma GCC diagnostic ignored "-Wshadow"
-
-// Disable the warning about nonliteral format strings because we construct
-// them dynamically when falling back to snprintf for FP formatting.
-# pragma GCC diagnostic ignored "-Wformat-nonliteral"
-#endif
-
-#if FMT_CLANG_VERSION
-# pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template"
-#endif
-
-#ifdef _SECURE_SCL
-# define FMT_SECURE_SCL _SECURE_SCL
-#else
-# define FMT_SECURE_SCL 0
-#endif
-
-// Check whether we can use unrestricted unions and use struct if not.
-#ifndef FMT_UNRESTRICTED_UNION
-# if FMT_MSC_VER >= 1900 || FMT_GCC_VERSION >= 406 || FMT_CLANG_VERSION >= 303
-# define FMT_UNRESTRICTED_UNION union
-# else
-# define FMT_UNRESTRICTED_UNION struct
-# endif
-#endif
-
-#if FMT_SECURE_SCL
-# include <iterator>
-#endif
-
#ifdef __has_builtin
# define FMT_HAS_BUILTIN(x) __has_builtin(x)
#else
# define FMT_HAS_BUILTIN(x) 0
#endif
-#ifdef __GNUC_LIBSTD__
-# define FMT_GNUC_LIBSTD_VERSION \
- (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__)
-#endif
-
#ifndef FMT_THROW
# if FMT_EXCEPTIONS
# if FMT_MSC_VER
@@ -131,13 +88,12 @@ FMT_END_NAMESPACE
do { \
static_cast<void>(sizeof(x)); \
assert(false); \
- } while (false);
+ } while (false)
# endif
#endif
#ifndef FMT_USE_USER_DEFINED_LITERALS
-// For Intel's compiler and NVIDIA's compiler both it and the system gcc/msc
-// must support UDLs.
+// For Intel and NVIDIA compilers both they and the system gcc/msc support UDLs.
# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \
FMT_MSC_VER >= 1900) && \
(!(FMT_ICC_VERSION || FMT_CUDA_VERSION) || FMT_ICC_VERSION >= 1500 || \
@@ -148,44 +104,35 @@ FMT_END_NAMESPACE
# endif
#endif
-// EDG C++ Front End based compilers (icc, nvcc) do not currently support UDL
-// templates.
-#if FMT_USE_USER_DEFINED_LITERALS && FMT_ICC_VERSION == 0 && \
- FMT_CUDA_VERSION == 0 && \
- ((FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L) || \
- (defined(FMT_CLANG_VERSION) && FMT_CLANG_VERSION >= 304))
-# define FMT_UDL_TEMPLATE 1
-#else
-# define FMT_UDL_TEMPLATE 0
-#endif
-
-#ifndef FMT_USE_EXTERN_TEMPLATES
-# ifndef FMT_HEADER_ONLY
-# define FMT_USE_EXTERN_TEMPLATES \
- ((FMT_CLANG_VERSION >= 209 && __cplusplus >= 201103L) || \
- (FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11))
+#ifndef FMT_USE_UDL_TEMPLATE
+// EDG front end based compilers (icc, nvcc) do not support UDL templates yet
+// and GCC 9 warns about them.
+# if FMT_USE_USER_DEFINED_LITERALS && FMT_ICC_VERSION == 0 && \
+ FMT_CUDA_VERSION == 0 && \
+ ((FMT_GCC_VERSION >= 600 && FMT_GCC_VERSION <= 900 && \
+ __cplusplus >= 201402L) || \
+ FMT_CLANG_VERSION >= 304)
+# define FMT_USE_UDL_TEMPLATE 1
# else
-# define FMT_USE_EXTERN_TEMPLATES 0
+# define FMT_USE_UDL_TEMPLATE 0
# endif
#endif
-#if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_trailing_return) || \
- FMT_MSC_VER >= 1600
-# define FMT_USE_TRAILING_RETURN 1
+#ifdef FMT_USE_INT128
+// Do nothing.
+#elif defined(__SIZEOF_INT128__)
+# define FMT_USE_INT128 1
#else
-# define FMT_USE_TRAILING_RETURN 0
+# define FMT_USE_INT128 0
#endif
// __builtin_clz is broken in clang with Microsoft CodeGen:
// https://github.com/fmtlib/fmt/issues/519
-#ifndef _MSC_VER
-# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz)
-# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
-# endif
-
-# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll)
-# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
-# endif
+#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)) && !FMT_MSC_VER
+# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
+#endif
+#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clzll)) && !FMT_MSC_VER
+# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
#endif
// Some compilers masquerade as both MSVC and GCC-likes or otherwise support
@@ -244,15 +191,16 @@ FMT_END_NAMESPACE
FMT_BEGIN_NAMESPACE
namespace internal {
-#ifndef FMT_USE_GRISU
-# define FMT_USE_GRISU 1
+// A fallback implementation of uintptr_t for systems that lack it.
+struct fallback_uintptr {
+ unsigned char value[sizeof(void*)];
+};
+#ifdef UINTPTR_MAX
+using uintptr_t = ::uintptr_t;
+#else
+using uintptr_t = fallback_uintptr;
#endif
-template <typename T> inline bool use_grisu() {
- return FMT_USE_GRISU && std::numeric_limits<double>::is_iec559 &&
- sizeof(T) <= sizeof(double);
-}
-
// An equivalent of `*reinterpret_cast<Dest*>(&source)` that doesn't produce
// undefined behavior (e.g. due to type aliasing).
// Example: uint64_t d = bit_cast<uint64_t>(2.718);
@@ -264,124 +212,72 @@ inline Dest bit_cast(const Source& source) {
return dest;
}
-// An implementation of begin and end for pre-C++11 compilers such as gcc 4.
-template <typename C>
-FMT_CONSTEXPR auto begin(const C& c) -> decltype(c.begin()) {
- return c.begin();
-}
-template <typename T, std::size_t N>
-FMT_CONSTEXPR T* begin(T (&array)[N]) FMT_NOEXCEPT {
- return array;
-}
-template <typename C> FMT_CONSTEXPR auto end(const C& c) -> decltype(c.end()) {
- return c.end();
-}
-template <typename T, std::size_t N>
-FMT_CONSTEXPR T* end(T (&array)[N]) FMT_NOEXCEPT {
- return array + N;
-}
-
-// For std::result_of in gcc 4.4.
-template <typename Result> struct function {
- template <typename T> struct result { typedef Result type; };
-};
+// An implementation of iterator_t for pre-C++20 systems.
+template <typename T>
+using iterator_t = decltype(std::begin(std::declval<T&>()));
-template <typename Allocator>
-typename Allocator::value_type* allocate(Allocator& alloc, std::size_t n) {
-#if __cplusplus >= 201103L || FMT_MSC_VER >= 1700
- return std::allocator_traits<Allocator>::allocate(alloc, n);
-#else
- return alloc.allocate(n);
+#ifndef FMT_USE_GRISU
+# define FMT_USE_GRISU 1
#endif
+
+template <typename T> inline bool use_grisu() {
+ return FMT_USE_GRISU && std::numeric_limits<double>::is_iec559 &&
+ sizeof(T) <= sizeof(double);
}
-} // namespace internal
-FMT_END_NAMESPACE
-FMT_BEGIN_NAMESPACE
-template <typename Range> class basic_writer;
+// A range with an iterator appending to a buffer.
+template <typename T> class buffer_range {
+ public:
+ using value_type = T;
+ using iterator = std::back_insert_iterator<buffer<T>>;
+
+ private:
+ iterator begin_;
+
+ public:
+ buffer_range(buffer<T>& buf) : begin_(std::back_inserter(buf)) {}
+ explicit buffer_range(iterator it) : begin_(it) {}
+ iterator begin() const { return begin_; }
+};
+// A range with the specified output iterator and value type.
template <typename OutputIt, typename T = typename OutputIt::value_type>
class output_range {
private:
OutputIt it_;
- // Unused yet.
- typedef void sentinel;
- sentinel end() const;
-
public:
- typedef OutputIt iterator;
- typedef T value_type;
+ using value_type = T;
+ using iterator = OutputIt;
explicit output_range(OutputIt it) : it_(it) {}
OutputIt begin() const { return it_; }
};
-// A range where begin() returns back_insert_iterator.
-template <typename Container>
-class back_insert_range
- : public output_range<std::back_insert_iterator<Container>> {
- typedef output_range<std::back_insert_iterator<Container>> base;
-
- public:
- typedef typename Container::value_type value_type;
-
- back_insert_range(Container& c) : base(std::back_inserter(c)) {}
- back_insert_range(typename base::iterator it) : base(it) {}
-};
-
-typedef basic_writer<back_insert_range<internal::buffer>> writer;
-typedef basic_writer<back_insert_range<internal::wbuffer>> wwriter;
-
-/** A formatting error such as invalid format string. */
-class format_error : public std::runtime_error {
- public:
- explicit format_error(const char* message) : std::runtime_error(message) {}
-
- explicit format_error(const std::string& message)
- : std::runtime_error(message) {}
-};
-
-namespace internal {
-
-#if FMT_SECURE_SCL
-template <typename T> struct checked {
- typedef stdext::checked_array_iterator<T*> type;
-};
-
-// Make a checked iterator to avoid warnings on MSVC.
-template <typename T>
-inline stdext::checked_array_iterator<T*> make_checked(T* p, std::size_t size) {
+#ifdef _SECURE_SCL
+// Make a checked iterator to avoid MSVC warnings.
+template <typename T> using checked_ptr = stdext::checked_array_iterator<T*>;
+template <typename T> checked_ptr<T> make_checked(T* p, std::size_t size) {
return {p, size};
}
#else
-template <typename T> struct checked { typedef T* type; };
+template <typename T> using checked_ptr = T*;
template <typename T> inline T* make_checked(T* p, std::size_t) { return p; }
#endif
template <typename T>
template <typename U>
-void basic_buffer<T>::append(const U* begin, const U* end) {
- std::size_t new_size = size_ + internal::to_unsigned(end - begin);
+void buffer<T>::append(const U* begin, const U* end) {
+ std::size_t new_size = size_ + to_unsigned(end - begin);
reserve(new_size);
- std::uninitialized_copy(begin, end,
- internal::make_checked(ptr_, capacity_) + size_);
+ std::uninitialized_copy(begin, end, make_checked(ptr_, capacity_) + size_);
size_ = new_size;
}
} // namespace internal
-// C++20 feature test, since r346892 Clang considers char8_t a fundamental
-// type in this mode. If this is the case __cpp_char8_t will be defined.
-#if !defined(__cpp_char8_t)
-// A UTF-8 code unit type.
-enum char8_t : unsigned char {};
-#endif
-
// A UTF-8 string view.
class u8string_view : public basic_string_view<char8_t> {
public:
- typedef char8_t char_type;
-
u8string_view(const char* s)
: basic_string_view<char8_t>(reinterpret_cast<const char8_t*>(s)) {}
u8string_view(const char* s, size_t count) FMT_NOEXCEPT
@@ -432,8 +328,7 @@ enum { inline_buffer_size = 500 };
*/
template <typename T, std::size_t SIZE = inline_buffer_size,
typename Allocator = std::allocator<T>>
-class basic_memory_buffer : private Allocator,
- public internal::basic_buffer<T> {
+class basic_memory_buffer : private Allocator, public internal::buffer<T> {
private:
T store_[SIZE];
@@ -507,7 +402,7 @@ void basic_memory_buffer<T, SIZE, Allocator>::grow(std::size_t size) {
std::size_t new_capacity = old_capacity + old_capacity / 2;
if (size > new_capacity) new_capacity = size;
T* old_data = this->data();
- T* new_data = internal::allocate<Allocator>(*this, new_capacity);
+ T* new_data = std::allocator_traits<Allocator>::allocate(*this, new_capacity);
// The following code doesn't throw, so the raw pointer above doesn't leak.
std::uninitialized_copy(old_data, old_data + this->size(),
internal::make_checked(new_data, new_capacity));
@@ -521,41 +416,20 @@ void basic_memory_buffer<T, SIZE, Allocator>::grow(std::size_t size) {
typedef basic_memory_buffer<char> memory_buffer;
typedef basic_memory_buffer<wchar_t> wmemory_buffer;
-namespace internal {
+/** A formatting error such as invalid format string. */
+class FMT_API format_error : public std::runtime_error {
+ public:
+ explicit format_error(const char* message) : std::runtime_error(message) {}
+ explicit format_error(const std::string& message)
+ : std::runtime_error(message) {}
+ ~format_error() FMT_NOEXCEPT;
+};
-template <typename Char> struct char_traits;
-
-template <> struct char_traits<char> {
- // Formats a floating-point number.
- template <typename T>
- FMT_API static int format_float(char* buffer, std::size_t size,
- const char* format, int precision, T value);
-};
-
-template <> struct char_traits<wchar_t> {
- template <typename T>
- FMT_API static int format_float(wchar_t* buffer, std::size_t size,
- const wchar_t* format, int precision,
- T value);
-};
-
-#if FMT_USE_EXTERN_TEMPLATES
-extern template int char_traits<char>::format_float<double>(char* buffer,
- std::size_t size,
- const char* format,
- int precision,
- double value);
-extern template int char_traits<char>::format_float<long double>(
- char* buffer, std::size_t size, const char* format, int precision,
- long double value);
-
-extern template int char_traits<wchar_t>::format_float<double>(
- wchar_t* buffer, std::size_t size, const wchar_t* format, int precision,
- double value);
-extern template int char_traits<wchar_t>::format_float<long double>(
- wchar_t* buffer, std::size_t size, const wchar_t* format, int precision,
- long double value);
-#endif
+template <typename Range> class basic_writer;
+using writer = basic_writer<internal::buffer_range<char>>;
+using wwriter = basic_writer<internal::buffer_range<wchar_t>>;
+
+namespace internal {
// A workaround for std::string not having mutable data() until C++17.
template <typename Char> inline Char* get_data(std::basic_string<Char>& s) {
@@ -567,7 +441,7 @@ inline typename Container::value_type* get_data(Container& c) {
}
template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
-inline typename checked<typename Container::value_type>::type reserve(
+inline checked_ptr<typename Container::value_type> reserve(
std::back_insert_iterator<Container>& it, std::size_t n) {
Container& c = internal::get_container(it);
std::size_t size = c.size();
@@ -708,30 +582,30 @@ FMT_CONSTEXPR bool is_negative(T) {
template <typename T> struct int_traits {
// Smallest of uint32_t and uint64_t that is large enough to represent
// all values of T.
- typedef typename std::conditional<std::numeric_limits<T>::digits <= 32,
- uint32_t, uint64_t>::type main_type;
+ using main_type =
+ conditional_t<std::numeric_limits<T>::digits <= 32, uint32_t, uint64_t>;
};
// Static data is placed in this class template to allow header-only
// configuration.
-template <typename T = void> struct FMT_API basic_data {
+template <typename T = void> struct FMT_EXTERN_TEMPLATE_API basic_data {
static const uint64_t POWERS_OF_10_64[];
static const uint32_t ZERO_OR_POWERS_OF_10_32[];
static const uint64_t ZERO_OR_POWERS_OF_10_64[];
static const uint64_t POW10_SIGNIFICANDS[];
static const int16_t POW10_EXPONENTS[];
static const char DIGITS[];
+ static const char HEX_DIGITS[];
static const char FOREGROUND_COLOR[];
static const char BACKGROUND_COLOR[];
static const char RESET_COLOR[5];
static const wchar_t WRESET_COLOR[5];
};
-#if FMT_USE_EXTERN_TEMPLATES
-extern template struct basic_data<void>;
-#endif
+FMT_EXTERN template struct basic_data<void>;
-typedef basic_data<> data;
+// This is a struct rather than a typedef to avoid shadowing warnings in gcc.
+struct data : basic_data<> {};
#ifdef FMT_BUILTIN_CLZLL
// Returns the number of decimal digits in n. Leading zeros are not counted
@@ -760,22 +634,40 @@ inline int count_digits(uint64_t n) {
}
#endif
+// Counts the number of digits in n. BITS = log2(radix).
+template <unsigned BITS, typename UInt> inline int count_digits(UInt n) {
+ int num_digits = 0;
+ do {
+ ++num_digits;
+ } while ((n >>= BITS) != 0);
+ return num_digits;
+}
+
+template <> int count_digits<4>(internal::fallback_uintptr n);
+
template <typename Char>
inline size_t count_code_points(basic_string_view<Char> s) {
return s.size();
}
// Counts the number of code points in a UTF-8 string.
-FMT_API size_t count_code_points(basic_string_view<char8_t> s);
+inline size_t count_code_points(basic_string_view<char8_t> s) {
+ const char8_t* data = s.data();
+ size_t num_code_points = 0;
+ for (size_t i = 0, size = s.size(); i != size; ++i) {
+ if ((data[i] & 0xc0) != 0x80) ++num_code_points;
+ }
+ return num_code_points;
+}
inline char8_t to_char8_t(char c) { return static_cast<char8_t>(c); }
template <typename InputIt, typename OutChar>
struct needs_conversion
- : std::integral_constant<
- bool, std::is_same<typename std::iterator_traits<InputIt>::value_type,
- char>::value &&
- std::is_same<OutChar, char8_t>::value> {};
+ : bool_constant<
+ std::is_same<typename std::iterator_traits<InputIt>::value_type,
+ char>::value &&
+ std::is_same<OutChar, char8_t>::value> {};
template <typename OutChar, typename InputIt, typename OutputIt,
FMT_ENABLE_IF(!needs_conversion<InputIt, OutChar>::value)>
@@ -971,7 +863,7 @@ inline Char* format_uint(Char* buffer, UInt value, int num_digits,
buffer += num_digits;
Char* end = buffer;
do {
- const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef";
+ const char* digits = upper ? "0123456789ABCDEF" : data::HEX_DIGITS;
unsigned digit = (value & ((1 << BASE_BITS) - 1));
*--buffer = static_cast<Char>(BASE_BITS < 4 ? static_cast<char>('0' + digit)
: digits[digit]);
@@ -979,6 +871,28 @@ inline Char* format_uint(Char* buffer, UInt value, int num_digits,
return end;
}
+template <unsigned BASE_BITS, typename Char>
+Char* format_uint(Char* buffer, internal::fallback_uintptr n, int num_digits,
+ bool = false) {
+ auto char_digits = std::numeric_limits<unsigned char>::digits / 4;
+ int start = (num_digits + char_digits - 1) / char_digits - 1;
+ if (int start_digits = num_digits % char_digits) {
+ unsigned value = n.value[start--];
+ buffer = format_uint<BASE_BITS>(buffer, value, start_digits);
+ }
+ for (; start >= 0; --start) {
+ unsigned value = n.value[start];
+ buffer += char_digits;
+ auto p = buffer;
+ for (int i = 0; i < char_digits; ++i) {
+ unsigned digit = (value & ((1 << BASE_BITS) - 1));
+ *--p = static_cast<Char>(data::HEX_DIGITS[digit]);
+ value >>= BASE_BITS;
+ }
+ }
+ return buffer;
+}
+
template <unsigned BASE_BITS, typename Char, typename It, typename UInt>
inline It format_uint(It out, UInt value, int num_digits, bool upper = false) {
// Buffer should be large enough to hold all digits (digits / BASE_BITS + 1)
@@ -1031,7 +945,8 @@ class utf16_to_utf8 {
FMT_API int convert(wstring_view s);
};
-FMT_API void format_windows_error(fmt::internal::buffer& out, int error_code,
+FMT_API void format_windows_error(fmt::internal::buffer<char>& out,
+ int error_code,
fmt::string_view message) FMT_NOEXCEPT;
#endif
@@ -1081,22 +996,18 @@ struct basic_format_specs : align_spec, core_format_specs {
typedef basic_format_specs<char> format_specs;
-template <typename Char, typename ErrorHandler>
-FMT_CONSTEXPR unsigned basic_parse_context<Char, ErrorHandler>::next_arg_id() {
- if (next_arg_id_ >= 0) return internal::to_unsigned(next_arg_id_++);
- on_error("cannot switch from manual to automatic argument indexing");
- return 0;
-}
-
namespace internal {
-// Formats value using Grisu2 algorithm:
+namespace grisu_options {
+enum { fixed = 1, grisu3 = 2 };
+}
+
+// Formats value using the Grisu algorithm:
// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf
template <typename Double, FMT_ENABLE_IF(sizeof(Double) == sizeof(uint64_t))>
-FMT_API bool grisu2_format(Double value, buffer& buf, int precision, bool fixed,
- int& exp);
+FMT_API bool grisu_format(Double, buffer<char>&, int, unsigned, int&);
template <typename Double, FMT_ENABLE_IF(sizeof(Double) != sizeof(uint64_t))>
-inline bool grisu2_format(Double, buffer&, int, bool, int&) {
+inline bool grisu_format(Double, buffer<char>&, int, unsigned, int&) {
return false;
}
@@ -1132,8 +1043,8 @@ template <typename Char, typename It> It write_exponent(int exp, It it) {
// The number is given as v = digits * pow(10, exp).
template <typename Char, typename It>
-It grisu2_prettify(const char* digits, int size, int exp, It it,
- gen_digits_params params) {
+It grisu_prettify(const char* digits, int size, int exp, It it,
+ gen_digits_params params) {
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
int full_exp = size + exp;
if (!params.fixed) {
@@ -1147,8 +1058,7 @@ It grisu2_prettify(const char* digits, int size, int exp, It it,
*it++ = static_cast<Char>(params.upper ? 'E' : 'e');
return write_exponent<Char>(exp, it);
}
- const int exp_threshold = 21;
- if (size <= full_exp && full_exp <= exp_threshold) {
+ if (size <= full_exp) {
// 1234e7 -> 12340000000[.0+]
it = copy_str<Char>(digits, digits + size, it);
it = std::fill_n(it, full_exp - size, static_cast<Char>('0'));
@@ -1160,12 +1070,13 @@ It grisu2_prettify(const char* digits, int size, int exp, It it,
} else if (full_exp > 0) {
// 1234e-2 -> 12.34[0+]
it = copy_str<Char>(digits, digits + full_exp, it);
- *it++ = static_cast<Char>('.');
if (!params.trailing_zeros) {
// Remove trailing zeros.
while (size > full_exp && digits[size - 1] == '0') --size;
+ if (size != full_exp) *it++ = static_cast<Char>('.');
return copy_str<Char>(digits + full_exp, digits + size, it);
}
+ *it++ = static_cast<Char>('.');
it = copy_str<Char>(digits + full_exp, digits + size, it);
if (params.num_digits > size) {
// Add trailing zeros.
@@ -1180,13 +1091,15 @@ It grisu2_prettify(const char* digits, int size, int exp, It it,
if (params.num_digits >= 0 && params.num_digits < num_zeros)
num_zeros = params.num_digits;
it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
+ if (!params.trailing_zeros)
+ while (size > 0 && digits[size - 1] == '0') --size;
it = copy_str<Char>(digits, digits + size, it);
}
return it;
}
template <typename Double>
-void sprintf_format(Double, internal::buffer&, core_format_specs);
+void sprintf_format(Double, internal::buffer<char>&, core_format_specs);
template <typename Handler>
FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) {
@@ -1337,34 +1250,22 @@ void arg_map<Context>::init(const basic_format_args<Context>& args) {
if (args.is_packed()) {
for (unsigned i = 0; /*nothing*/; ++i) {
internal::type arg_type = args.type(i);
- switch (arg_type) {
- case internal::none_type:
- return;
- case internal::named_arg_type:
- push_back(args.values_[i]);
- break;
- default:
- break; // Do nothing.
- }
+ if (arg_type == internal::none_type) return;
+ if (arg_type == internal::named_arg_type) push_back(args.values_[i]);
}
}
for (unsigned i = 0;; ++i) {
- switch (args.args_[i].type_) {
- case internal::none_type:
- return;
- case internal::named_arg_type:
- push_back(args.args_[i].value_);
- break;
- default:
- break; // Do nothing.
- }
+ auto type = args.args_[i].type_;
+ if (type == internal::none_type) return;
+ if (type == internal::named_arg_type) push_back(args.args_[i].value_);
}
}
-template <typename Range> class arg_formatter_base {
+template <typename Range, typename ErrorHandler = internal::error_handler>
+class arg_formatter_base {
public:
typedef typename Range::value_type char_type;
- typedef decltype(internal::declval<Range>().begin()) iterator;
+ typedef decltype(std::declval<Range>().begin()) iterator;
typedef basic_format_specs<char_type> format_specs;
private:
@@ -1389,10 +1290,7 @@ template <typename Range> class arg_formatter_base {
}
void write_pointer(const void* p) {
- format_specs specs = specs_ ? *specs_ : format_specs();
- specs.flags = HASH_FLAG;
- specs.type = 'x';
- writer_.write_int(reinterpret_cast<uintptr_t>(p), specs);
+ writer_.write_pointer(internal::bit_cast<internal::uintptr_t>(p), specs_);
}
protected:
@@ -1421,20 +1319,24 @@ template <typename Range> class arg_formatter_base {
return out();
}
- template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value ||
- std::is_same<T, char_type>::value)>
+ template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
iterator operator()(T value) {
- // MSVC2013 fails to compile separate overloads for bool and char_type so
- // use std::is_same instead.
- if (std::is_same<T, bool>::value) {
- if (specs_ && specs_->type) return (*this)(value ? 1 : 0);
- write(value != 0);
- } else if (std::is_same<T, char_type>::value) {
- internal::handle_char_specs(
- specs_, char_spec_handler(*this, static_cast<char_type>(value)));
- } else {
- specs_ ? writer_.write_int(value, *specs_) : writer_.write(value);
- }
+ if (specs_)
+ writer_.write_int(value, *specs_);
+ else
+ writer_.write(value);
+ return out();
+ }
+
+ iterator operator()(char_type value) {
+ internal::handle_char_specs(
+ specs_, char_spec_handler(*this, static_cast<char_type>(value)));
+ return out();
+ }
+
+ iterator operator()(bool value) {
+ if (specs_ && specs_->type) return (*this)(value ? 1 : 0);
+ write(value != 0);
return out();
}
@@ -1444,7 +1346,7 @@ template <typename Range> class arg_formatter_base {
return out();
}
- struct char_spec_handler : internal::error_handler {
+ struct char_spec_handler : ErrorHandler {
arg_formatter_base& formatter;
char_type value;
@@ -1528,7 +1430,7 @@ FMT_CONSTEXPR unsigned parse_nonnegative_int(const Char*& begin,
return value;
}
-template <typename Context> class custom_formatter : public function<bool> {
+template <typename Context> class custom_formatter {
private:
typedef typename Context::char_type char_type;
@@ -1555,8 +1457,7 @@ template <typename T> struct is_integer {
};
};
-template <typename ErrorHandler>
-class width_checker : public function<unsigned long long> {
+template <typename ErrorHandler> class width_checker {
public:
explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {}
@@ -1576,8 +1477,7 @@ class width_checker : public function<unsigned long long> {
ErrorHandler& handler_;
};
-template <typename ErrorHandler>
-class precision_checker : public function<unsigned long long> {
+template <typename ErrorHandler> class precision_checker {
public:
explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {}
@@ -1718,6 +1618,13 @@ FMT_CONSTEXPR void set_dynamic_spec(T& value, FormatArg arg, ErrorHandler eh) {
struct auto_id {};
+template <typename Context>
+FMT_CONSTEXPR typename Context::format_arg get_arg(Context& ctx, unsigned id) {
+ auto arg = ctx.arg(id);
+ if (!arg) ctx.on_error("argument index out of range");
+ return arg;
+}
+
// The standard format specifier handler with checking.
template <typename ParseContext, typename Context>
class specs_handler : public specs_setter<typename Context::char_type> {
@@ -1772,10 +1679,9 @@ struct string_view_metadata {
: offset_(view.data() - primary_string.data()), size_(view.size()) {}
FMT_CONSTEXPR string_view_metadata(std::size_t offset, std::size_t size)
: offset_(offset), size_(size) {}
- template <typename S, FMT_ENABLE_IF(internal::is_string<S>::value)>
- FMT_CONSTEXPR basic_string_view<FMT_CHAR(S)> to_view(S&& str) const {
- const auto view = to_string_view(str);
- return basic_string_view<FMT_CHAR(S)>(view.data() + offset_, size_);
+ template <typename Char>
+ FMT_CONSTEXPR basic_string_view<Char> to_view(const Char* str) const {
+ return {str + offset_, size_};
}
std::size_t offset_;
@@ -1799,15 +1705,14 @@ template <typename Char> struct arg_ref {
}
Kind kind;
- FMT_UNRESTRICTED_UNION value {
+ union value {
FMT_CONSTEXPR value() : index(0u) {}
FMT_CONSTEXPR value(unsigned id) : index(id) {}
FMT_CONSTEXPR value(string_view_metadata n) : name(n) {}
unsigned index;
string_view_metadata name;
- }
- val;
+ } val;
};
// Format specifiers with width and precision resolved at formatting rather
@@ -1991,7 +1896,7 @@ template <typename Char, typename Handler>
FMT_CONSTEXPR const Char* parse_precision(const Char* begin, const Char* end,
Handler&& handler) {
++begin;
- auto c = begin != end ? *begin : 0;
+ auto c = begin != end ? *begin : Char();
if ('0' <= c && c <= '9') {
handler.on_precision(parse_nonnegative_int(begin, end, handler));
} else if (c == '{') {
@@ -2074,7 +1979,7 @@ inline bool find<false, char>(const char* first, const char* last, char value,
const char*& out) {
out = static_cast<const char*>(
std::memchr(first, value, internal::to_unsigned(last - first)));
- return out != FMT_NULL;
+ return out != nullptr;
}
template <typename Handler, typename Char> struct id_adapter {
@@ -2096,7 +2001,7 @@ FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> format_str,
FMT_CONSTEXPR void operator()(const Char* begin, const Char* end) {
if (begin == end) return;
for (;;) {
- const Char* p = FMT_NULL;
+ const Char* p = nullptr;
if (!find<IS_CONSTEXPR>(begin, end, '}', p))
return handler_.on_text(begin, end);
++p;
@@ -2144,11 +2049,16 @@ FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> format_str,
template <typename T, typename ParseContext>
FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs(
ParseContext& ctx) {
- // GCC 7.2 requires initializer.
- typedef typename ParseContext::char_type char_type;
- typename std::conditional<is_formattable<T, format_context>::value,
- formatter<T, char_type>,
- internal::fallback_formatter<T, char_type>>::type f;
+ using char_type = typename ParseContext::char_type;
+ using context = buffer_context<char_type>;
+ using mapped_type =
+ conditional_t<internal::mapped_type_constant<T, context>::value !=
+ internal::custom_type,
+ decltype(arg_mapper<context>().map(std::declval<T>())), T>;
+ conditional_t<has_formatter<mapped_type, context>::value,
+ formatter<mapped_type, char_type>,
+ internal::fallback_formatter<T, char_type>>
+ f;
return f.parse(ctx);
}
@@ -2179,7 +2089,7 @@ class format_string_checker {
FMT_CONSTEXPR void on_replacement_field(const Char*) {}
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin, const Char*) {
- context_.advance_to(begin);
+ advance_to(context_, begin);
return arg_id_ < NUM_ARGS ? parse_funcs_[arg_id_](context_) : begin;
}
@@ -2212,7 +2122,7 @@ FMT_CONSTEXPR bool do_check_format_string(basic_string_view<Char> s,
}
template <typename... Args, typename S,
- typename std::enable_if<is_compile_string<S>::value, int>::type>
+ enable_if_t<(is_compile_string<S>::value), int>>
void check_format_string(S format_str) {
typedef typename S::char_type char_t;
FMT_CONSTEXPR_DECL bool invalid_format =
@@ -2221,14 +2131,6 @@ void check_format_string(S format_str) {
(void)invalid_format;
}
-// Specifies whether to format T using the standard formatter.
-// It is not possible to use get_type in formatter specialization directly
-// because of a bug in MSVC.
-template <typename Context, typename T>
-struct format_type
- : std::integral_constant<bool, get_type<Context, T>::value != custom_type> {
-};
-
template <template <typename> class Handler, typename Spec, typename Context>
void handle_dynamic_spec(Spec& value, arg_ref<typename Context::char_type> ref,
Context& ctx,
@@ -2252,10 +2154,7 @@ void handle_dynamic_spec(Spec& value, arg_ref<typename Context::char_type> ref,
/** The default argument formatter. */
template <typename Range>
-class arg_formatter
- : public internal::function<
- typename internal::arg_formatter_base<Range>::iterator>,
- public internal::arg_formatter_base<Range> {
+class arg_formatter : public internal::arg_formatter_base<Range> {
private:
typedef typename Range::value_type char_type;
typedef internal::arg_formatter_base<Range> base;
@@ -2277,8 +2176,8 @@ class arg_formatter
\endrst
*/
explicit arg_formatter(context_type& ctx,
- basic_parse_context<char_type>* parse_ctx = FMT_NULL,
- format_specs* spec = FMT_NULL)
+ basic_parse_context<char_type>* parse_ctx = nullptr,
+ format_specs* spec = nullptr)
: base(Range(ctx.out()), spec, ctx.locale()),
ctx_(ctx),
parse_ctx_(parse_ctx) {}
@@ -2299,7 +2198,7 @@ class arg_formatter
An error returned by an operating system or a language runtime,
for example a file opening error.
*/
-class system_error : public std::runtime_error {
+class FMT_API system_error : public std::runtime_error {
private:
FMT_API void init(int err_code, string_view format_str, format_args args);
@@ -2332,6 +2231,7 @@ class system_error : public std::runtime_error {
: std::runtime_error("") {
init(error_code, message, make_format_args(args...));
}
+ ~system_error() FMT_NOEXCEPT;
int error_code() const { return error_code_; }
};
@@ -2352,7 +2252,7 @@ class system_error : public std::runtime_error {
may look like "Unknown error -1" and is platform-dependent.
\endrst
*/
-FMT_API void format_system_error(internal::buffer& out, int error_code,
+FMT_API void format_system_error(internal::buffer<char>& out, int error_code,
fmt::string_view message) FMT_NOEXCEPT;
/**
@@ -2362,7 +2262,7 @@ FMT_API void format_system_error(internal::buffer& out, int error_code,
template <typename Range> class basic_writer {
public:
typedef typename Range::value_type char_type;
- typedef decltype(internal::declval<Range>().begin()) iterator;
+ typedef decltype(std::declval<Range>().begin()) iterator;
typedef basic_format_specs<char_type> format_specs;
private:
@@ -2466,16 +2366,6 @@ template <typename Range> class basic_writer {
string_view get_prefix() const { return string_view(prefix, prefix_size); }
- // Counts the number of digits in abs_value. BITS = log2(radix).
- template <unsigned BITS> int count_digits() const {
- unsigned_type n = abs_value;
- int num_digits = 0;
- do {
- ++num_digits;
- } while ((n >>= BITS) != 0);
- return num_digits;
- }
-
int_writer(basic_writer<Range>& w, Int value, const Spec& s)
: writer(w),
spec(s),
@@ -2521,7 +2411,7 @@ template <typename Range> class basic_writer {
prefix[prefix_size++] = '0';
prefix[prefix_size++] = static_cast<char>(spec.type);
}
- int num_digits = count_digits<4>();
+ int num_digits = internal::count_digits<4>(abs_value);
writer.write_int(num_digits, get_prefix(), spec,
hex_writer{*this, num_digits});
}
@@ -2540,13 +2430,13 @@ template <typename Range> class basic_writer {
prefix[prefix_size++] = '0';
prefix[prefix_size++] = static_cast<char>(spec.type);
}
- int num_digits = count_digits<1>();
+ int num_digits = internal::count_digits<1>(abs_value);
writer.write_int(num_digits, get_prefix(), spec,
bin_writer<1>{abs_value, num_digits});
}
void on_oct() {
- int num_digits = count_digits<3>();
+ int num_digits = internal::count_digits<3>(abs_value);
if (spec.has(HASH_FLAG) && spec.precision <= num_digits) {
// Octal prefix '0' is counted as a digit, so only add it if precision
// is not greater than the number of digits.
@@ -2578,7 +2468,9 @@ template <typename Range> class basic_writer {
num_writer{abs_value, size, sep});
}
- void on_error() { FMT_THROW(format_error("invalid type specifier")); }
+ FMT_NORETURN void on_error() {
+ FMT_THROW(format_error("invalid type specifier"));
+ }
};
// Writes a formatted integer.
@@ -2611,7 +2503,7 @@ template <typename Range> class basic_writer {
struct double_writer {
char sign;
- internal::buffer& buffer;
+ internal::buffer<char>& buffer;
size_t size() const { return buffer.size() + (sign ? 1 : 0); }
size_t width() const { return size(); }
@@ -2624,21 +2516,21 @@ template <typename Range> class basic_writer {
class grisu_writer {
private:
- internal::buffer& digits_;
+ internal::buffer<char>& digits_;
size_t size_;
char sign_;
int exp_;
internal::gen_digits_params params_;
public:
- grisu_writer(char sign, internal::buffer& digits, int exp,
+ grisu_writer(char sign, internal::buffer<char>& digits, int exp,
const internal::gen_digits_params& params)
: digits_(digits), sign_(sign), exp_(exp), params_(params) {
int num_digits = static_cast<int>(digits.size());
int full_exp = num_digits + exp - 1;
int precision = params.num_digits > 0 ? params.num_digits : 11;
params_.fixed |= full_exp >= -4 && full_exp < precision;
- auto it = internal::grisu2_prettify<char>(
+ auto it = internal::grisu_prettify<char>(
digits.data(), num_digits, exp, internal::counting_iterator<char>(),
params_);
size_ = it.count();
@@ -2650,8 +2542,8 @@ template <typename Range> class basic_writer {
template <typename It> void operator()(It&& it) {
if (sign_) *it++ = static_cast<char_type>(sign_);
int num_digits = static_cast<int>(digits_.size());
- it = internal::grisu2_prettify<char_type>(digits_.data(), num_digits,
- exp_, it, params_);
+ it = internal::grisu_prettify<char_type>(digits_.data(), num_digits, exp_,
+ it, params_);
}
};
@@ -2672,7 +2564,22 @@ template <typename Range> class basic_writer {
}
};
- template <typename Char> friend class internal::arg_formatter_base;
+ template <typename UIntPtr> struct pointer_writer {
+ UIntPtr value;
+ int num_digits;
+
+ size_t size() const { return num_digits + 2; }
+ size_t width() const { return size(); }
+
+ template <typename It> void operator()(It&& it) const {
+ *it++ = static_cast<char_type>('0');
+ *it++ = static_cast<char_type>('x');
+ it = internal::format_uint<4, char_type>(it, value, num_digits);
+ }
+ };
+
+ template <typename Char, typename ErrorHandler>
+ friend class internal::arg_formatter_base;
public:
/** Constructs a ``basic_writer`` object. */
@@ -2722,8 +2629,9 @@ template <typename Range> class basic_writer {
auto&& it = reserve(1);
*it++ = value;
}
- void write(wchar_t value) {
- static_assert(std::is_same<char_type, wchar_t>::value, "");
+
+ template <typename Char, FMT_ENABLE_IF(std::is_same<Char, char_type>::value)>
+ void write(Char value) {
auto&& it = reserve(1);
*it++ = value;
}
@@ -2759,12 +2667,14 @@ template <typename Range> class basic_writer {
write(data, size, spec);
}
- template <typename T, FMT_ENABLE_IF(std::is_same<T, void>::value)>
- void write(const T* p) {
- format_specs specs;
- specs.flags = HASH_FLAG;
- specs.type = 'x';
- write_int(reinterpret_cast<uintptr_t>(p), specs);
+ template <typename UIntPtr>
+ void write_pointer(UIntPtr value, const align_spec* spec) {
+ int num_digits = internal::count_digits<4>(value);
+ auto pw = pointer_writer<UIntPtr>{value, num_digits};
+ if (!spec) return pw(reserve(num_digits + 2));
+ align_spec as = *spec;
+ if (as.align() == ALIGN_DEFAULT) as.align_ = ALIGN_RIGHT;
+ write_padded(as, pw);
}
};
@@ -2799,7 +2709,9 @@ struct float_spec_handler {
if (type == 'A') upper = true;
}
- void on_error() { FMT_THROW(format_error("invalid type specifier")); }
+ FMT_NORETURN void on_error() {
+ FMT_THROW(format_error("invalid type specifier"));
+ }
};
template <typename Range>
@@ -2832,11 +2744,12 @@ void basic_writer<Range>::write_double(T value, const format_specs& spec) {
memory_buffer buffer;
int exp = 0;
int precision = spec.has_precision() || !spec.type ? spec.precision : 6;
+ unsigned options = handler.fixed ? internal::grisu_options::fixed : 0;
bool use_grisu = fmt::internal::use_grisu<T>() &&
(spec.type != 'a' && spec.type != 'A' && spec.type != 'e' &&
spec.type != 'E') &&
- internal::grisu2_format(static_cast<double>(value), buffer,
- precision, handler.fixed, exp);
+ internal::grisu_format(static_cast<double>(value), buffer,
+ precision, options, exp);
if (!use_grisu) internal::sprintf_format(value, buffer, spec);
if (handler.as_percentage) {
@@ -2996,53 +2909,24 @@ class format_int {
std::string str() const { return std::string(str_, size()); }
};
-// Formats a decimal integer value writing into buffer and returns
-// a pointer to the end of the formatted string. This function doesn't
-// write a terminating null character.
-template <typename T>
-FMT_DEPRECATED inline void format_decimal(char*& buffer, T value) {
- typedef typename internal::int_traits<T>::main_type main_type;
- main_type abs_value = static_cast<main_type>(value);
- if (internal::is_negative(value)) {
- *buffer++ = '-';
- abs_value = 0 - abs_value;
- }
- if (abs_value < 100) {
- if (abs_value < 10) {
- *buffer++ = static_cast<char>('0' + abs_value);
- return;
- }
- unsigned index = static_cast<unsigned>(abs_value * 2);
- *buffer++ = internal::data::DIGITS[index];
- *buffer++ = internal::data::DIGITS[index + 1];
- return;
- }
- int num_digits = internal::count_digits(abs_value);
- internal::format_decimal<char>(
- internal::make_checked(buffer, internal::to_unsigned(num_digits)),
- abs_value, num_digits);
- buffer += num_digits;
-}
-
-// Formatter of objects of type T.
+// A formatter specialization for the core types corresponding to internal::type
+// constants.
template <typename T, typename Char>
struct formatter<T, Char,
- typename std::enable_if<internal::format_type<
- typename buffer_context<Char>::type, T>::value>::type> {
- FMT_CONSTEXPR formatter() : format_str_(FMT_NULL) {}
+ enable_if_t<internal::type_constant<T, Char>::value !=
+ internal::custom_type>> {
+ FMT_CONSTEXPR formatter() : format_str_(nullptr) {}
// Parses format specifiers stopping either at the end of the range or at the
// terminating '}'.
template <typename ParseContext>
- FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext& ctx) {
+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
format_str_ = ctx.begin();
- typedef internal::dynamic_specs_handler<ParseContext> handler_type;
- auto type =
- internal::get_type<typename buffer_context<Char>::type, T>::value;
+ using handler_type = internal::dynamic_specs_handler<ParseContext>;
+ auto type = internal::type_constant<T, Char>::value;
internal::specs_checker<handler_type> handler(handler_type(specs_, ctx),
type);
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
- auto type_spec = specs_.type;
auto eh = ctx.error_handler();
switch (type) {
case internal::none_type:
@@ -3054,27 +2938,27 @@ struct formatter<T, Char,
case internal::long_long_type:
case internal::ulong_long_type:
case internal::bool_type:
- handle_int_type_spec(type_spec,
+ handle_int_type_spec(specs_.type,
internal::int_type_checker<decltype(eh)>(eh));
break;
case internal::char_type:
handle_char_specs(
- &specs_, internal::char_specs_checker<decltype(eh)>(type_spec, eh));
+ &specs_, internal::char_specs_checker<decltype(eh)>(specs_.type, eh));
break;
case internal::double_type:
case internal::long_double_type:
- handle_float_type_spec(type_spec,
+ handle_float_type_spec(specs_.type,
internal::float_type_checker<decltype(eh)>(eh));
break;
case internal::cstring_type:
internal::handle_cstring_type_spec(
- type_spec, internal::cstring_type_checker<decltype(eh)>(eh));
+ specs_.type, internal::cstring_type_checker<decltype(eh)>(eh));
break;
case internal::string_type:
- internal::check_string_type_spec(type_spec, eh);
+ internal::check_string_type_spec(specs_.type, eh);
break;
case internal::pointer_type:
- internal::check_pointer_type_spec(type_spec, eh);
+ internal::check_pointer_type_spec(specs_.type, eh);
break;
case internal::custom_type:
// Custom format specifiers should be checked in parse functions of
@@ -3090,10 +2974,10 @@ struct formatter<T, Char,
specs_.width_, specs_.width_ref, ctx, format_str_);
internal::handle_dynamic_spec<internal::precision_checker>(
specs_.precision, specs_.precision_ref, ctx, format_str_);
- typedef output_range<typename FormatContext::iterator,
- typename FormatContext::char_type>
- range_type;
- return visit_format_arg(arg_formatter<range_type>(ctx, FMT_NULL, &specs_),
+ using range_type =
+ internal::output_range<typename FormatContext::iterator,
+ typename FormatContext::char_type>;
+ return visit_format_arg(arg_formatter<range_type>(ctx, nullptr, &specs_),
internal::make_arg<FormatContext>(val));
}
@@ -3102,6 +2986,43 @@ struct formatter<T, Char,
const Char* format_str_;
};
+#define FMT_FORMAT_AS(Type, Base) \
+ template <typename Char> \
+ struct formatter<Type, Char> : formatter<Base, Char> { \
+ template <typename FormatContext> \
+ auto format(const Type& val, FormatContext& ctx) -> decltype(ctx.out()) { \
+ return formatter<Base, Char>::format(val, ctx); \
+ } \
+ }
+
+FMT_FORMAT_AS(signed char, int);
+FMT_FORMAT_AS(unsigned char, unsigned);
+FMT_FORMAT_AS(short, int);
+FMT_FORMAT_AS(unsigned short, unsigned);
+FMT_FORMAT_AS(long, long long);
+FMT_FORMAT_AS(unsigned long, unsigned long long);
+FMT_FORMAT_AS(float, double);
+FMT_FORMAT_AS(Char*, const Char*);
+FMT_FORMAT_AS(std::basic_string<Char>, basic_string_view<Char>);
+FMT_FORMAT_AS(std::nullptr_t, const void*);
+FMT_FORMAT_AS(internal::std_string_view<Char>, basic_string_view<Char>);
+
+template <typename Char>
+struct formatter<void*, Char> : formatter<const void*, Char> {
+ template <typename FormatContext>
+ auto format(void* val, FormatContext& ctx) -> decltype(ctx.out()) {
+ return formatter<const void*, Char>::format(val, ctx);
+ }
+};
+
+template <typename Char, size_t N>
+struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> {
+ template <typename FormatContext>
+ auto format(const Char* val, FormatContext& ctx) -> decltype(ctx.out()) {
+ return formatter<basic_string_view<Char>, Char>::format(val, ctx);
+ }
+};
+
// A formatter for types known only at run time such as variant alternatives.
//
// Usage:
@@ -3135,7 +3056,8 @@ template <typename Char = char> class dynamic_formatter {
auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
handle_specs(ctx);
internal::specs_checker<null_handler> checker(
- null_handler(), internal::get_type<FormatContext, T>::value);
+ null_handler(),
+ internal::mapped_type_constant<T, FormatContext>::value);
checker.on_align(specs_.align());
if (specs_.flags == 0)
; // Do nothing.
@@ -3146,10 +3068,10 @@ template <typename Char = char> class dynamic_formatter {
else if (specs_.has(HASH_FLAG))
checker.on_hash();
if (specs_.precision != -1) checker.end_precision();
- typedef output_range<typename FormatContext::iterator,
- typename FormatContext::char_type>
+ typedef internal::output_range<typename FormatContext::iterator,
+ typename FormatContext::char_type>
range;
- visit_format_arg(arg_formatter<range>(ctx, FMT_NULL, &specs_),
+ visit_format_arg(arg_formatter<range>(ctx, nullptr, &specs_),
internal::make_arg<FormatContext>(val));
return ctx.out();
}
@@ -3175,6 +3097,12 @@ basic_format_context<Range, Char>::arg(basic_string_view<char_type> name) {
return arg;
}
+template <typename Char, typename ErrorHandler>
+FMT_CONSTEXPR void advance_to(basic_parse_context<Char, ErrorHandler>& ctx,
+ const Char* p) {
+ ctx.advance_to(ctx.begin() + (p - &*ctx.begin()));
+}
+
template <typename ArgFormatter, typename Char, typename Context>
struct format_handler : internal::error_handler {
typedef typename ArgFormatter::range range;
@@ -3202,7 +3130,7 @@ struct format_handler : internal::error_handler {
void on_arg_id(basic_string_view<Char> id) { arg = context.arg(id); }
void on_replacement_field(const Char* p) {
- parse_context.advance_to(p);
+ advance_to(parse_context, p);
internal::custom_formatter<Context> f(parse_context, context);
if (!visit_format_arg(f, arg))
context.advance_to(
@@ -3210,7 +3138,7 @@ struct format_handler : internal::error_handler {
}
const Char* on_format_specs(const Char* begin, const Char* end) {
- parse_context.advance_to(begin);
+ advance_to(parse_context, begin);
internal::custom_formatter<Context> f(parse_context, context);
if (visit_format_arg(f, arg)) return parse_context.begin();
basic_format_specs<Char> specs;
@@ -3221,7 +3149,7 @@ struct format_handler : internal::error_handler {
arg.type());
begin = parse_format_specs(begin, end, handler);
if (begin == end || *begin != '}') on_error("missing '}' in format string");
- parse_context.advance_to(begin);
+ advance_to(parse_context, begin);
context.advance_to(
visit_format_arg(ArgFormatter(context, &parse_context, &specs), arg));
return begin;
@@ -3247,14 +3175,17 @@ typename Context::iterator vformat_to(
// Example:
// auto s = format("{}", ptr(p));
template <typename T> inline const void* ptr(const T* p) { return p; }
+template <typename T> inline const void* ptr(const std::unique_ptr<T>& p) {
+ return p.get();
+}
+template <typename T> inline const void* ptr(const std::shared_ptr<T>& p) {
+ return p.get();
+}
template <typename It, typename Char> struct arg_join {
It begin;
It end;
basic_string_view<Char> sep;
-
- arg_join(It begin, It end, basic_string_view<Char> sep)
- : begin(begin), end(end), sep(sep) {}
};
template <typename It, typename Char>
@@ -3278,28 +3209,43 @@ struct formatter<arg_join<It, Char>, Char>
}
};
+/**
+ Returns an object that formats the iterator range `[begin, end)` with elements
+ separated by `sep`.
+ */
template <typename It>
arg_join<It, char> join(It begin, It end, string_view sep) {
- return arg_join<It, char>(begin, end, sep);
+ return {begin, end, sep};
}
template <typename It>
arg_join<It, wchar_t> join(It begin, It end, wstring_view sep) {
- return arg_join<It, wchar_t>(begin, end, sep);
+ return {begin, end, sep};
}
-// The following causes ICE in gcc 4.4.
-#if FMT_USE_TRAILING_RETURN && (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 405)
+// gcc 4.4 on join: internal compiler error: in tsubst_copy, at cp/pt.c:10122
+#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 405
+/**
+ \rst
+ Returns an object that formats `range` with elements separated by `sep`.
+
+ **Example**::
+
+ std::vector<int> v = {1, 2, 3};
+ fmt::print("{}", fmt::join(v, ", "));
+ // Output: "1, 2, 3"
+ \endrst
+ */
template <typename Range>
-auto join(const Range& range, string_view sep)
- -> arg_join<decltype(internal::begin(range)), char> {
- return join(internal::begin(range), internal::end(range), sep);
+arg_join<internal::iterator_t<const Range>, char> join(const Range& range,
+ string_view sep) {
+ return join(std::begin(range), std::end(range), sep);
}
template <typename Range>
-auto join(const Range& range, wstring_view sep)
- -> arg_join<decltype(internal::begin(range)), wchar_t> {
- return join(internal::begin(range), internal::end(range), sep);
+arg_join<internal::iterator_t<const Range>, wchar_t> join(const Range& range,
+ wstring_view sep) {
+ return join(std::begin(range), std::end(range), sep);
}
#endif
@@ -3315,21 +3261,15 @@ auto join(const Range& range, wstring_view sep)
std::string answer = fmt::to_string(42);
\endrst
*/
-template <typename T> std::string to_string(const T& value) {
- std::string str;
- internal::container_buffer<std::string> buf(str);
- writer(buf).write(value);
- return str;
+template <typename T> inline std::string to_string(const T& value) {
+ return format("{}", value);
}
/**
Converts *value* to ``std::wstring`` using the default format for type *T*.
*/
-template <typename T> std::wstring to_wstring(const T& value) {
- std::wstring str;
- internal::container_buffer<std::wstring> buf(str);
- wwriter(buf).write(value);
- return str;
+template <typename T> inline std::wstring to_wstring(const T& value) {
+ return format(L"{}", value);
}
template <typename Char, std::size_t SIZE>
@@ -3338,29 +3278,29 @@ std::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE>& buf) {
}
template <typename Char>
-typename buffer_context<Char>::type::iterator internal::vformat_to(
- internal::basic_buffer<Char>& buf, basic_string_view<Char> format_str,
- basic_format_args<typename buffer_context<Char>::type> args) {
- typedef back_insert_range<internal::basic_buffer<Char>> range;
+typename buffer_context<Char>::iterator internal::vformat_to(
+ internal::buffer<Char>& buf, basic_string_view<Char> format_str,
+ basic_format_args<buffer_context<Char>> args) {
+ using range = buffer_range<Char>;
return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str),
args);
}
-template <typename S, typename Char = FMT_CHAR(S),
+template <typename S, typename Char = char_t<S>,
FMT_ENABLE_IF(internal::is_string<S>::value)>
-inline typename buffer_context<Char>::type::iterator vformat_to(
- internal::basic_buffer<Char>& buf, const S& format_str,
- basic_format_args<typename buffer_context<Char>::type> args) {
+inline typename buffer_context<Char>::iterator vformat_to(
+ internal::buffer<Char>& buf, const S& format_str,
+ basic_format_args<buffer_context<Char>> args) {
return internal::vformat_to(buf, to_string_view(format_str), args);
}
template <typename S, typename... Args, std::size_t SIZE = inline_buffer_size,
- typename Char = typename internal::char_t<S>::type>
-inline typename buffer_context<Char>::type::iterator format_to(
+ typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
+inline typename buffer_context<Char>::iterator format_to(
basic_memory_buffer<Char, SIZE>& buf, const S& format_str,
const Args&... args) {
internal::check_format_string<Args...>(format_str);
- typedef typename buffer_context<Char>::type context;
+ using context = buffer_context<Char>;
format_arg_store<context, Args...> as{args...};
return internal::vformat_to(buf, to_string_view(format_str),
basic_format_args<context>(as));
@@ -3396,12 +3336,12 @@ template <typename It> class is_output_iterator {
// The compiler reveals this property only at the point of *actually
// dereferencing* the iterator!
template <typename U>
- static decltype(*(internal::declval<U>())) test(std::input_iterator_tag);
+ static decltype(*(std::declval<U>())) test(std::input_iterator_tag);
template <typename U> static char& test(std::output_iterator_tag);
template <typename U> static const char& test(...);
typedef decltype(test<It>(typename it_category<It>::type{})) type;
- typedef typename std::remove_reference<type>::type result;
+ typedef remove_reference_t<type> result;
public:
static const bool value = !std::is_const<result>::value;
@@ -3421,12 +3361,14 @@ struct format_args_t {
type;
};
-template <typename String, typename OutputIt, typename... Args,
- FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)>
+template <typename S, typename OutputIt, typename... Args,
+ FMT_ENABLE_IF(
+ internal::is_output_iterator<OutputIt>::value &&
+ !internal::is_contiguous_back_insert_iterator<OutputIt>::value)>
inline OutputIt vformat_to(
- OutputIt out, const String& format_str,
- typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
- typedef output_range<OutputIt, FMT_CHAR(String)> range;
+ OutputIt out, const S& format_str,
+ typename format_args_t<OutputIt, char_t<S>>::type args) {
+ typedef internal::output_range<OutputIt, char_t<S>> range;
return vformat_to<arg_formatter<range>>(range(out),
to_string_view(format_str), args);
}
@@ -3443,13 +3385,13 @@ inline OutputIt vformat_to(
\endrst
*/
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 S& format_str, const Args&... args) {
+inline OutputIt format_to(OutputIt out, const S& format_str,
+ const Args&... args) {
+ static_assert(internal::is_output_iterator<OutputIt>::value &&
+ internal::is_string<S>::value,
+ "");
internal::check_format_string<Args...>(format_str);
- typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;
+ typedef typename format_context_t<OutputIt, char_t<S>>::type context;
format_arg_store<context, Args...> as{args...};
return vformat_to(out, to_string_view(format_str),
basic_format_args<context>(as));
@@ -3504,7 +3446,7 @@ inline format_to_n_result<OutputIt> format_to_n(OutputIt out, std::size_t n,
const S& format_str,
const Args&... args) {
internal::check_format_string<Args...>(format_str);
- typedef FMT_CHAR(S) Char;
+ using Char = char_t<S>;
format_arg_store<typename format_to_n_context<OutputIt, Char>::type, Args...>
as(args...);
return vformat_to_n(out, n, to_string_view(format_str),
@@ -3514,7 +3456,7 @@ inline format_to_n_result<OutputIt> format_to_n(OutputIt out, std::size_t n,
template <typename Char>
inline std::basic_string<Char> internal::vformat(
basic_string_view<Char> format_str,
- basic_format_args<typename buffer_context<Char>::type> args) {
+ basic_format_args<buffer_context<Char>> args) {
basic_memory_buffer<Char> buffer;
internal::vformat_to(buffer, format_str, args);
return fmt::to_string(buffer);
@@ -3533,7 +3475,7 @@ inline std::size_t formatted_size(string_view format_str, const Args&... args) {
#if FMT_USE_USER_DEFINED_LITERALS
namespace internal {
-# if FMT_UDL_TEMPLATE
+# if FMT_USE_UDL_TEMPLATE
template <typename Char, Char... CHARS> class udl_formatter {
public:
template <typename... Args>
@@ -3556,7 +3498,7 @@ template <typename Char> struct udl_formatter {
return format(str, std::forward<Args>(args)...);
}
};
-# endif // FMT_UDL_TEMPLATE
+# endif // FMT_USE_UDL_TEMPLATE
template <typename Char> struct udl_arg {
const Char* str;
@@ -3569,11 +3511,16 @@ template <typename Char> struct udl_arg {
} // namespace internal
inline namespace literals {
-# if FMT_UDL_TEMPLATE
+# if FMT_USE_UDL_TEMPLATE
+# pragma GCC diagnostic push
+# if FMT_CLANG_VERSION
+# pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template"
+# endif
template <typename Char, Char... CHARS>
FMT_CONSTEXPR internal::udl_formatter<Char, CHARS...> operator""_format() {
return {};
}
+# pragma GCC diagnostic pop
# else
/**
\rst
@@ -3593,7 +3540,7 @@ inline internal::udl_formatter<wchar_t> operator"" _format(const wchar_t* s,
std::size_t) {
return {s};
}
-# endif // FMT_UDL_TEMPLATE
+# endif // FMT_USE_UDL_TEMPLATE
/**
\rst
@@ -3665,9 +3612,4 @@ FMT_END_NAMESPACE
# define FMT_FUNC
#endif
-// Restore warnings.
-#if FMT_GCC_VERSION >= 406 || FMT_CLANG_VERSION
-# pragma GCC diagnostic pop
-#endif
-
#endif // FMT_FORMAT_H_
diff --git a/src/third_party/fmt/dist/include/fmt/locale.h b/src/third_party/fmt/dist/include/fmt/locale.h
index 4a33b666b87..1faf9723429 100644
--- a/src/third_party/fmt/dist/include/fmt/locale.h
+++ b/src/third_party/fmt/dist/include/fmt/locale.h
@@ -15,57 +15,58 @@ FMT_BEGIN_NAMESPACE
namespace internal {
template <typename Char>
-typename buffer_context<Char>::type::iterator vformat_to(
- const std::locale& loc, basic_buffer<Char>& buf,
+typename buffer_context<Char>::iterator vformat_to(
+ const std::locale& loc, 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;
+ basic_format_args<buffer_context<Char>> args) {
+ using range = buffer_range<Char>;
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) {
+std::basic_string<Char> vformat(const std::locale& loc,
+ basic_string_view<Char> format_str,
+ basic_format_args<buffer_context<Char>> args) {
basic_memory_buffer<Char> buffer;
internal::vformat_to(loc, buffer, format_str, args);
return fmt::to_string(buffer);
}
} // namespace internal
-template <typename S, typename Char = FMT_CHAR(S)>
+template <typename S, typename Char = char_t<S>>
inline std::basic_string<Char> vformat(
const std::locale& loc, const S& format_str,
- basic_format_args<typename buffer_context<Char>::type> args) {
+ basic_format_args<buffer_context<Char>> 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) {
+template <typename S, typename... Args, typename Char = char_t<S>>
+inline std::basic_string<Char> format(const std::locale& loc,
+ const S& format_str,
+ const Args&... args) {
return internal::vformat(loc, to_string_view(format_str),
{internal::make_args_checked(format_str, args...)});
}
-template <typename String, typename OutputIt, typename... Args,
- FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)>
-inline OutputIt 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;
+template <typename S, typename OutputIt, typename... Args,
+ typename Char = enable_if_t<
+ internal::is_output_iterator<OutputIt>::value, char_t<S>>>
+inline OutputIt vformat_to(OutputIt out, const std::locale& loc,
+ const S& format_str,
+ typename format_args_t<OutputIt, Char>::type args) {
+ using range = internal::output_range<OutputIt, Char>;
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,
- FMT_ENABLE_IF(internal::is_string<S>::value&&
- internal::is_output_iterator<OutputIt>::value)>
+ FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value&&
+ internal::is_string<S>::value)>
inline OutputIt 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;
+ using context = typename format_context_t<OutputIt, char_t<S>>::type;
format_arg_store<context, Args...> as{args...};
return vformat_to(out, loc, to_string_view(format_str),
basic_format_args<context>(as));
diff --git a/src/third_party/fmt/dist/include/fmt/ostream.h b/src/third_party/fmt/dist/include/fmt/ostream.h
index 5f70fed6180..49aa58054c6 100644
--- a/src/third_party/fmt/dist/include/fmt/ostream.h
+++ b/src/third_party/fmt/dist/include/fmt/ostream.h
@@ -19,10 +19,10 @@ template <class Char> class formatbuf : public std::basic_streambuf<Char> {
typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
- basic_buffer<Char>& buffer_;
+ buffer<Char>& buffer_;
public:
- formatbuf(basic_buffer<Char>& buffer) : buffer_(buffer) {}
+ formatbuf(buffer<Char>& buf) : buffer_(buf) {}
protected:
// The put-area is actually always empty. This makes the implementation
@@ -56,8 +56,8 @@ template <typename Char> struct test_stream : std::basic_ostream<Char> {
template <typename T, typename Char> class is_streamable {
private:
template <typename U>
- static decltype((void)(internal::declval<test_stream<Char>&>()
- << internal::declval<U>()),
+ static decltype((void)(std::declval<test_stream<Char>&>()
+ << std::declval<U>()),
std::true_type())
test(int);
@@ -71,34 +71,33 @@ template <typename T, typename Char> class is_streamable {
// Write the content of buf to os.
template <typename Char>
-void write(std::basic_ostream<Char>& os, basic_buffer<Char>& buf) {
- const Char* data = buf.data();
+void write(std::basic_ostream<Char>& os, buffer<Char>& buf) {
+ const Char* buf_data = buf.data();
typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;
UnsignedStreamSize size = buf.size();
UnsignedStreamSize max_size =
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
do {
UnsignedStreamSize n = size <= max_size ? size : max_size;
- os.write(data, static_cast<std::streamsize>(n));
- data += n;
+ os.write(buf_data, static_cast<std::streamsize>(n));
+ buf_data += n;
size -= n;
} while (size != 0);
}
template <typename Char, typename T>
-void format_value(basic_buffer<Char>& buffer, const T& value) {
- internal::formatbuf<Char> format_buf(buffer);
+void format_value(buffer<Char>& buf, const T& value) {
+ internal::formatbuf<Char> format_buf(buf);
std::basic_ostream<Char> output(&format_buf);
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
output << value;
- buffer.resize(buffer.size());
+ buf.resize(buf.size());
}
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename T, typename Char>
-struct fallback_formatter<
- T, Char,
- typename std::enable_if<internal::is_streamable<T, Char>::value>::type>
+struct fallback_formatter<T, Char,
+ enable_if_t<internal::is_streamable<T, Char>::value>>
: formatter<basic_string_view<Char>, Char> {
template <typename Context>
auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
@@ -110,21 +109,14 @@ struct fallback_formatter<
};
} // namespace internal
-// Disable conversion to int if T has an overloaded operator<< which is a free
-// function (not a member of std::ostream).
-template <typename T, typename Char> struct convert_to_int<T, Char, void> {
- static const bool value = convert_to_int<T, Char, int>::value &&
- !internal::is_streamable<T, Char>::value;
-};
-
template <typename Char>
-inline void vprint(
- std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
- basic_format_args<typename buffer_context<Char>::type> args) {
+void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
+ basic_format_args<buffer_context<Char>> args) {
basic_memory_buffer<Char> buffer;
internal::vformat_to(buffer, format_str, args);
internal::write(os, buffer);
}
+
/**
\rst
Prints formatted data to the stream *os*.
@@ -135,8 +127,8 @@ inline void vprint(
\endrst
*/
template <typename S, typename... Args,
- FMT_ENABLE_IF(internal::is_string<S>::value)>
-inline void print(std::basic_ostream<FMT_CHAR(S)>& os, const S& format_str,
+ typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
+inline void print(std::basic_ostream<Char>& os, const S& format_str,
const Args&... args) {
vprint(os, to_string_view(format_str),
{internal::make_args_checked(format_str, args...)});
diff --git a/src/third_party/fmt/dist/include/fmt/posix.h b/src/third_party/fmt/dist/include/fmt/posix.h
index b919e25ff16..e5394f40051 100644
--- a/src/third_party/fmt/dist/include/fmt/posix.h
+++ b/src/third_party/fmt/dist/include/fmt/posix.h
@@ -133,7 +133,7 @@ class buffered_file {
public:
// Constructs a buffered_file object which doesn't represent any file.
- buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
+ buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
// Destroys the object closing the file it represents if any.
FMT_API ~buffered_file() FMT_NOEXCEPT;
@@ -144,13 +144,13 @@ class buffered_file {
public:
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
- other.file_ = FMT_NULL;
+ other.file_ = nullptr;
}
buffered_file& operator=(buffered_file&& other) {
close();
file_ = other.file_;
- other.file_ = FMT_NULL;
+ other.file_ = nullptr;
return *this;
}
@@ -261,12 +261,6 @@ class file {
// Returns the memory page size.
long getpagesize();
-#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
- !defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \
- !defined(__NEWLIB_H__)
-# define FMT_LOCALE
-#endif
-
#ifdef FMT_LOCALE
// A "C" numeric locale.
class Locale {
@@ -295,7 +289,7 @@ class Locale {
public:
typedef locale_t Type;
- Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
+ Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", nullptr)) {
if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
}
~Locale() { freelocale(locale_); }
@@ -305,7 +299,7 @@ class Locale {
// Converts string to floating-point number and advances str past the end
// of the parsed input.
double strtod(const char*& str) const {
- char* end = FMT_NULL;
+ char* end = nullptr;
double result = strtod_l(str, &end, locale_);
str = end;
return result;
diff --git a/src/third_party/fmt/dist/include/fmt/prepare.h b/src/third_party/fmt/dist/include/fmt/prepare.h
index 2e063e1e8e4..6c149c2509e 100644
--- a/src/third_party/fmt/dist/include/fmt/prepare.h
+++ b/src/third_party/fmt/dist/include/fmt/prepare.h
@@ -40,7 +40,7 @@ template <typename Char> struct format_part {
which_arg_id which;
- FMT_UNRESTRICTED_UNION value {
+ union value {
FMT_CONSTEXPR value() : index(0u) {}
FMT_CONSTEXPR value(unsigned id) : index(id) {}
FMT_CONSTEXPR value(internal::string_view_metadata id)
@@ -48,8 +48,7 @@ template <typename Char> struct format_part {
unsigned index;
internal::string_view_metadata named_index;
- }
- val;
+ } val;
};
struct specification {
@@ -89,7 +88,7 @@ template <typename Char> struct format_part {
which_value which;
std::size_t end_of_argument_id;
- FMT_UNRESTRICTED_UNION value {
+ union value {
FMT_CONSTEXPR value() : arg_id(0u) {}
FMT_CONSTEXPR value(unsigned id) : arg_id(id) {}
FMT_CONSTEXPR value(named_argument_id named_id)
@@ -100,8 +99,7 @@ template <typename Char> struct format_part {
internal::string_view_metadata named_arg_id;
internal::string_view_metadata text;
specification spec;
- }
- val;
+ } val;
};
namespace internal {
@@ -185,8 +183,8 @@ class format_preparation_handler : public internal::error_handler {
template <typename Format, typename PreparedPartsProvider, typename... Args>
class prepared_format {
public:
- typedef FMT_CHAR(Format) char_type;
- typedef format_part<char_type> format_part_t;
+ using char_type = char_t<Format>;
+ using format_part_t = format_part<char_type>;
prepared_format(Format f)
: format_(std::move(f)), parts_provider_(to_string_view(format_)) {}
@@ -216,8 +214,9 @@ class prepared_format {
std::basic_string<char_type> format(const Args&... args) const {
basic_memory_buffer<char_type> buffer;
- typedef back_insert_range<internal::basic_buffer<char_type>> range;
- this->vformat_to(range(buffer), make_args_checked(format_, args...));
+ using range = buffer_range<char_type>;
+ this->vformat_to(range(buffer), basic_format_args<context>{
+ make_args_checked(format_, args...)});
return to_string(buffer);
}
@@ -225,8 +224,9 @@ class prepared_format {
inline std::back_insert_iterator<Container> format_to(
std::back_insert_iterator<Container> out, const Args&... args) const {
internal::container_buffer<Container> buffer(internal::get_container(out));
- typedef back_insert_range<internal::basic_buffer<char_type>> range;
- this->vformat_to(range(buffer), make_args_checked(format_, args...));
+ using range = buffer_range<char_type>;
+ this->vformat_to(range(buffer), basic_format_args<context>{
+ make_args_checked(format_, args...)});
return out;
}
@@ -239,21 +239,23 @@ class prepared_format {
}
template <std::size_t SIZE = inline_buffer_size>
- inline typename buffer_context<char_type>::type::iterator format_to(
+ inline typename buffer_context<char_type>::iterator format_to(
basic_memory_buffer<char_type, SIZE>& buf, const Args&... args) const {
- typedef back_insert_range<internal::basic_buffer<char_type>> range;
- return this->vformat_to(range(buf), make_args_checked(format_, args...));
+ using range = buffer_range<char_type>;
+ return this->vformat_to(
+ range(buf),
+ basic_format_args<context>{make_args_checked(format_, args...)});
}
private:
- typedef typename buffer_context<char_type>::type context;
+ typedef buffer_context<char_type> context;
- template <typename Range>
- typename context::iterator vformat_to(Range out,
- basic_format_args<context> args) const {
+ template <typename Range, typename Context>
+ auto vformat_to(Range out, basic_format_args<Context> args) const ->
+ typename Context::iterator {
const auto format_view = internal::to_string_view(format_);
basic_parse_context<char_type> parse_ctx(format_view);
- context ctx(out.begin(), args);
+ Context ctx(out.begin(), args);
const auto& parts = parts_provider_.parts();
for (auto part_it = parts.begin(); part_it != parts.end(); ++part_it) {
@@ -262,7 +264,7 @@ class prepared_format {
switch (part.which) {
case format_part_t::which_value::text: {
- const auto text = value.text.to_view(format_view);
+ const auto text = value.text.to_view(format_view.data());
auto output = ctx.out();
auto&& it = internal::reserve(output, text.size());
it = std::copy_n(text.begin(), text.size(), it);
@@ -276,16 +278,17 @@ class prepared_format {
case format_part_t::which_value::named_argument_id: {
advance_parse_context_to_specification(parse_ctx, part);
- const auto named_arg_id = value.named_arg_id.to_view(format_view);
+ const auto named_arg_id =
+ value.named_arg_id.to_view(format_view.data());
format_arg<Range>(parse_ctx, ctx, named_arg_id);
} break;
case format_part_t::which_value::specification: {
const auto& arg_id_value = value.spec.arg_id.val;
- const auto arg =
- value.spec.arg_id.which ==
- format_part_t::argument_id::which_arg_id::index
- ? ctx.arg(arg_id_value.index)
- : ctx.arg(arg_id_value.named_index.to_view(format_));
+ const auto arg = value.spec.arg_id.which ==
+ format_part_t::argument_id::which_arg_id::index
+ ? ctx.arg(arg_id_value.index)
+ : ctx.arg(arg_id_value.named_index.to_view(
+ to_string_view(format_).data()));
auto specs = value.spec.parsed_specs;
@@ -297,7 +300,7 @@ class prepared_format {
check_prepared_specs(specs, arg.type());
advance_parse_context_to_specification(parse_ctx, part);
ctx.advance_to(
- visit_format_arg(arg_formatter<Range>(ctx, FMT_NULL, &specs), arg));
+ visit_format_arg(arg_formatter<Range>(ctx, nullptr, &specs), arg));
} break;
}
}
@@ -310,7 +313,7 @@ class prepared_format {
const format_part_t& part) const {
const auto view = to_string_view(format_);
const auto specification_begin = view.data() + part.end_of_argument_id;
- parse_ctx.advance_to(specification_begin);
+ advance_to(parse_ctx, specification_begin);
}
template <typename Range, typename Context, typename Id>
@@ -351,7 +354,7 @@ class prepared_format {
template <typename Format> class compiletime_prepared_parts_type_provider {
private:
- typedef FMT_CHAR(Format) char_type;
+ using char_type = char_t<Format>;
class count_handler {
private:
@@ -440,9 +443,8 @@ template <typename Format> class compiletime_prepared_parts_type_provider {
typedef format_part<char_type> value_type;
};
- typedef typename std::conditional<static_cast<bool>(number_of_format_parts),
- format_parts_array<number_of_format_parts>,
- empty>::type type;
+ using type = conditional_t<static_cast<bool>(number_of_format_parts),
+ format_parts_array<number_of_format_parts>, empty>;
};
template <typename Parts> class compiletime_prepared_parts_collector {
@@ -539,14 +541,14 @@ struct parts_container_concept_check : std::true_type {
template <typename T> static std::false_type has_add_check(check_second);
template <typename T>
static decltype(
- (void)declval<T>().add(declval<typename T::format_part_type>()),
+ (void)std::declval<T>().add(std::declval<typename T::format_part_type>()),
std::true_type()) has_add_check(check_first);
typedef decltype(has_add_check<PartsContainer>(check_first())) has_add;
static_assert(has_add::value, "PartsContainer doesn't provide add() method");
template <typename T> static std::false_type has_last_check(check_second);
template <typename T>
- static decltype((void)declval<T>().last(),
+ static decltype((void)std::declval<T>().last(),
std::true_type()) has_last_check(check_first);
typedef decltype(has_last_check<PartsContainer>(check_first())) has_last;
static_assert(has_last::value,
@@ -555,8 +557,8 @@ struct parts_container_concept_check : std::true_type {
template <typename T>
static std::false_type has_substitute_last_check(check_second);
template <typename T>
- static decltype((void)declval<T>().substitute_last(
- declval<typename T::format_part_type>()),
+ static decltype((void)std::declval<T>().substitute_last(
+ std::declval<typename T::format_part_type>()),
std::true_type()) has_substitute_last_check(check_first);
typedef decltype(has_substitute_last_check<PartsContainer>(
check_first())) has_substitute_last;
@@ -565,7 +567,7 @@ struct parts_container_concept_check : std::true_type {
template <typename T> static std::false_type has_begin_check(check_second);
template <typename T>
- static decltype((void)declval<T>().begin(),
+ static decltype((void)std::declval<T>().begin(),
std::true_type()) has_begin_check(check_first);
typedef decltype(has_begin_check<PartsContainer>(check_first())) has_begin;
static_assert(has_begin::value,
@@ -573,7 +575,7 @@ struct parts_container_concept_check : std::true_type {
template <typename T> static std::false_type has_end_check(check_second);
template <typename T>
- static decltype((void)declval<T>().end(),
+ static decltype((void)std::declval<T>().end(),
std::true_type()) has_end_check(check_first);
typedef decltype(has_end_check<PartsContainer>(check_first())) has_end;
static_assert(has_end::value, "PartsContainer doesn't provide end() method");
@@ -626,19 +628,19 @@ class parts_container {
format_part_type last() { return parts_.back(); }
- auto begin() -> decltype(internal::declval<Container>().begin()) {
+ auto begin() -> decltype(std::declval<Container>().begin()) {
return parts_.begin();
}
- auto begin() const -> decltype(internal::declval<const Container>().begin()) {
+ auto begin() const -> decltype(std::declval<const Container>().begin()) {
return parts_.begin();
}
- auto end() -> decltype(internal::declval<Container>().end()) {
+ auto end() -> decltype(std::declval<Container>().end()) {
return parts_.end();
}
- auto end() const -> decltype(internal::declval<const Container>().end()) {
+ auto end() const -> decltype(std::declval<const Container>().end()) {
return parts_.end();
}
@@ -649,7 +651,7 @@ class parts_container {
// Delegate preparing to preparator, to take advantage of a partial
// specialization.
template <typename Format, typename... Args> struct preparator {
- typedef parts_container<FMT_CHAR(Format)> container;
+ typedef parts_container<char_t<Format>> container;
typedef typename basic_prepared_format<Format, container, Args...>::type
prepared_format_type;
@@ -674,9 +676,8 @@ struct compiletime_format_tag {};
struct runtime_format_tag {};
template <typename Format> struct format_tag {
- typedef typename std::conditional<is_compile_string<Format>::value,
- compiletime_format_tag,
- runtime_format_tag>::type type;
+ using type = conditional_t<is_compile_string<Format>::value,
+ compiletime_format_tag, runtime_format_tag>;
};
#if FMT_USE_CONSTEXPR
diff --git a/src/third_party/fmt/dist/include/fmt/printf.h b/src/third_party/fmt/dist/include/fmt/printf.h
index 50a3de48679..c2e9f9bf1af 100644
--- a/src/third_party/fmt/dist/include/fmt/printf.h
+++ b/src/third_party/fmt/dist/include/fmt/printf.h
@@ -38,13 +38,13 @@ template <> struct int_checker<true> {
static bool fits_in_int(int) { return true; }
};
-class printf_precision_handler : public function<int> {
+class printf_precision_handler {
public:
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
int operator()(T value) {
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(format_error("number is too big"));
- return static_cast<int>(value);
+ return (std::max)(static_cast<int>(value), 0);
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
@@ -55,7 +55,7 @@ class printf_precision_handler : public function<int> {
};
// An argument visitor that returns true iff arg is a zero integer.
-class is_zero_int : public function<bool> {
+class is_zero_int {
public:
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
bool operator()(T value) {
@@ -72,8 +72,7 @@ template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {};
template <> struct make_unsigned_or_bool<bool> { typedef bool type; };
-template <typename T, typename Context>
-class arg_converter : public function<void> {
+template <typename T, typename Context> class arg_converter {
private:
typedef typename Context::char_type Char;
@@ -91,15 +90,14 @@ class arg_converter : public function<void> {
template <typename U, FMT_ENABLE_IF(std::is_integral<U>::value)>
void operator()(U value) {
bool is_signed = type_ == 'd' || type_ == 'i';
- typedef typename std::conditional<std::is_same<T, void>::value, U, T>::type
- TargetType;
- if (const_check(sizeof(TargetType) <= sizeof(int))) {
+ using target_type = conditional_t<std::is_same<T, void>::value, U, T>;
+ if (const_check(sizeof(target_type) <= sizeof(int))) {
// Extra casts are used to silence warnings.
if (is_signed) {
arg_ = internal::make_arg<Context>(
- static_cast<int>(static_cast<TargetType>(value)));
+ static_cast<int>(static_cast<target_type>(value)));
} else {
- typedef typename make_unsigned_or_bool<TargetType>::type Unsigned;
+ typedef typename make_unsigned_or_bool<target_type>::type Unsigned;
arg_ = internal::make_arg<Context>(
static_cast<unsigned>(static_cast<Unsigned>(value)));
}
@@ -130,7 +128,7 @@ void convert_arg(basic_format_arg<Context>& arg, Char type) {
}
// Converts an integer argument to char for printf.
-template <typename Context> class char_converter : public function<void> {
+template <typename Context> class char_converter {
private:
basic_format_arg<Context>& arg_;
@@ -149,8 +147,7 @@ template <typename Context> class char_converter : public function<void> {
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
-template <typename Char>
-class printf_width_handler : public function<unsigned> {
+template <typename Char> class printf_width_handler {
private:
typedef basic_format_specs<Char> format_specs;
@@ -180,7 +177,7 @@ class printf_width_handler : public function<unsigned> {
};
template <typename Char, typename Context>
-void printf(basic_buffer<Char>& buf, basic_string_view<Char> format,
+void printf(buffer<Char>& buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
Context(std::back_inserter(buf), format, args).format();
}
@@ -197,10 +194,7 @@ using internal::printf; // For printing into memory_buffer.
template <typename Range> class printf_arg_formatter;
-template <typename OutputIt, typename Char,
- typename ArgFormatter = printf_arg_formatter<
- back_insert_range<internal::basic_buffer<Char>>>>
-class basic_printf_context;
+template <typename OutputIt, typename Char> class basic_printf_context;
/**
\rst
@@ -208,16 +202,14 @@ class basic_printf_context;
\endrst
*/
template <typename Range>
-class printf_arg_formatter
- : public internal::function<
- typename internal::arg_formatter_base<Range>::iterator>,
- public internal::arg_formatter_base<Range> {
+class printf_arg_formatter : public internal::arg_formatter_base<Range> {
+ public:
+ typedef decltype(std::declval<Range>().begin()) iterator;
+
private:
typedef typename Range::value_type char_type;
- typedef decltype(internal::declval<Range>().begin()) iterator;
typedef internal::arg_formatter_base<Range> base;
- typedef basic_printf_context<iterator, char_type, printf_arg_formatter>
- context_type;
+ typedef basic_printf_context<iterator, char_type> context_type;
context_type& context_;
@@ -328,16 +320,12 @@ template <typename T> struct printf_formatter {
};
/** This template formats data and writes the output to a writer. */
-template <typename OutputIt, typename Char, typename ArgFormatter>
-class basic_printf_context {
+template <typename OutputIt, typename Char> class basic_printf_context {
public:
/** The character type for the output. */
- typedef Char char_type;
- typedef basic_format_arg<basic_printf_context> format_arg;
-
- template <typename T> struct formatter_type {
- typedef printf_formatter<T> type;
- };
+ using char_type = Char;
+ using format_arg = basic_format_arg<basic_printf_context>;
+ template <typename T> using formatter_type = printf_formatter<T>;
private:
typedef basic_format_specs<char_type> format_specs;
@@ -379,13 +367,15 @@ class basic_printf_context {
}
/** Formats stored arguments and writes the output to the range. */
+ template <typename ArgFormatter =
+ printf_arg_formatter<internal::buffer_range<Char>>>
OutputIt format();
};
-template <typename OutputIt, typename Char, typename AF>
-void basic_printf_context<OutputIt, Char, AF>::parse_flags(format_specs& spec,
- const Char*& it,
- const Char* end) {
+template <typename OutputIt, typename Char>
+void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& spec,
+ const Char*& it,
+ const Char* end) {
for (; it != end; ++it) {
switch (*it) {
case '-':
@@ -409,9 +399,9 @@ void basic_printf_context<OutputIt, Char, AF>::parse_flags(format_specs& spec,
}
}
-template <typename OutputIt, typename Char, typename AF>
-typename basic_printf_context<OutputIt, Char, AF>::format_arg
-basic_printf_context<OutputIt, Char, AF>::get_arg(unsigned arg_index) {
+template <typename OutputIt, typename Char>
+typename basic_printf_context<OutputIt, Char>::format_arg
+basic_printf_context<OutputIt, Char>::get_arg(unsigned arg_index) {
if (arg_index == std::numeric_limits<unsigned>::max())
arg_index = parse_ctx_.next_arg_id();
else
@@ -419,8 +409,8 @@ basic_printf_context<OutputIt, Char, AF>::get_arg(unsigned arg_index) {
return internal::get_arg(*this, arg_index);
}
-template <typename OutputIt, typename Char, typename AF>
-unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
+template <typename OutputIt, typename Char>
+unsigned basic_printf_context<OutputIt, Char>::parse_header(
const Char*& it, const Char* end, format_specs& spec) {
unsigned arg_index = std::numeric_limits<unsigned>::max();
char_type c = *it;
@@ -457,8 +447,9 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
return arg_index;
}
-template <typename OutputIt, typename Char, typename AF>
-OutputIt basic_printf_context<OutputIt, Char, AF>::format() {
+template <typename OutputIt, typename Char>
+template <typename ArgFormatter>
+OutputIt basic_printf_context<OutputIt, Char>::format() {
auto out = this->out();
const Char* start = parse_ctx_.begin();
const Char* end = parse_ctx_.end();
@@ -567,7 +558,7 @@ OutputIt basic_printf_context<OutputIt, Char, AF>::format() {
start = it;
// Format argument.
- visit_format_arg(AF(out, spec, *this), arg);
+ visit_format_arg(ArgFormatter(out, spec, *this), arg);
}
return std::copy(start, it, out);
}
@@ -578,8 +569,8 @@ template <typename Buffer> struct basic_printf_context_t {
type;
};
-typedef basic_printf_context_t<internal::buffer>::type printf_context;
-typedef basic_printf_context_t<internal::wbuffer>::type wprintf_context;
+typedef basic_printf_context_t<internal::buffer<char>>::type printf_context;
+typedef basic_printf_context_t<internal::buffer<wchar_t>>::type wprintf_context;
typedef basic_format_args<printf_context> printf_args;
typedef basic_format_args<wprintf_context> wprintf_args;
@@ -608,11 +599,11 @@ inline format_arg_store<wprintf_context, Args...> make_wprintf_args(
return {args...};
}
-template <typename S, typename Char = FMT_CHAR(S)>
+template <typename S, typename Char = char_t<S>>
inline std::basic_string<Char> vsprintf(
const S& format,
basic_format_args<
- typename basic_printf_context_t<internal::basic_buffer<Char>>::type>
+ typename basic_printf_context_t<internal::buffer<Char>>::type>
args) {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
@@ -629,21 +620,18 @@ inline std::basic_string<Char> vsprintf(
\endrst
*/
template <typename S, typename... Args,
- FMT_ENABLE_IF(internal::is_string<S>::value)>
-inline std::basic_string<FMT_CHAR(S)> sprintf(const S& format,
- const Args&... args) {
- internal::check_format_string<Args...>(format);
- typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
- typedef typename basic_printf_context_t<buffer>::type context;
+ typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
+inline std::basic_string<Char> sprintf(const S& format, const Args&... args) {
+ using context = typename basic_printf_context_t<internal::buffer<Char>>::type;
format_arg_store<context, Args...> as{args...};
return vsprintf(to_string_view(format), basic_format_args<context>(as));
}
-template <typename S, typename Char = FMT_CHAR(S)>
+template <typename S, typename Char = char_t<S>>
inline int vfprintf(
std::FILE* f, const S& format,
basic_format_args<
- typename basic_printf_context_t<internal::basic_buffer<Char>>::type>
+ typename basic_printf_context_t<internal::buffer<Char>>::type>
args) {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
@@ -663,20 +651,18 @@ inline int vfprintf(
\endrst
*/
template <typename S, typename... Args,
- FMT_ENABLE_IF(internal::is_string<S>::value)>
+ typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
inline int fprintf(std::FILE* f, 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;
+ using context = typename basic_printf_context_t<internal::buffer<Char>>::type;
format_arg_store<context, Args...> as{args...};
return vfprintf(f, to_string_view(format), basic_format_args<context>(as));
}
-template <typename S, typename Char = FMT_CHAR(S)>
+template <typename S, typename Char = char_t<S>>
inline int vprintf(
const S& format,
basic_format_args<
- typename basic_printf_context_t<internal::basic_buffer<Char>>::type>
+ typename basic_printf_context_t<internal::buffer<Char>>::type>
args) {
return vfprintf(stdout, to_string_view(format), args);
}
@@ -693,18 +679,17 @@ inline int vprintf(
template <typename S, typename... Args,
FMT_ENABLE_IF(internal::is_string<S>::value)>
inline int printf(const S& format_str, const Args&... args) {
- internal::check_format_string<Args...>(format_str);
- typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
- typedef typename basic_printf_context_t<buffer>::type context;
+ using buffer = internal::buffer<char_t<S>>;
+ using context = typename basic_printf_context_t<buffer>::type;
format_arg_store<context, Args...> as{args...};
return vprintf(to_string_view(format_str), basic_format_args<context>(as));
}
-template <typename S, typename Char = FMT_CHAR(S)>
+template <typename S, typename Char = char_t<S>>
inline int vfprintf(
std::basic_ostream<Char>& os, const S& format,
basic_format_args<
- typename basic_printf_context_t<internal::basic_buffer<Char>>::type>
+ typename basic_printf_context_t<internal::buffer<Char>>::type>
args) {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
@@ -712,6 +697,18 @@ inline int vfprintf(
return static_cast<int>(buffer.size());
}
+/** Formats arguments and writes the output to the range. */
+template <typename ArgFormatter, typename Char,
+ typename Context =
+ basic_printf_context<typename ArgFormatter::iterator, Char>>
+typename ArgFormatter::iterator vprintf(internal::buffer<Char>& out,
+ basic_string_view<Char> format_str,
+ basic_format_args<Context> args) {
+ typename ArgFormatter::iterator iter(out);
+ Context(iter, format_str, args).template format<ArgFormatter>();
+ return iter;
+}
+
/**
\rst
Prints formatted data to the stream *os*.
@@ -721,13 +718,10 @@ inline int vfprintf(
fmt::fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
-template <typename S, typename... Args,
- FMT_ENABLE_IF(internal::is_string<S>::value)>
-inline int fprintf(std::basic_ostream<FMT_CHAR(S)>& os, const S& format_str,
+template <typename S, typename... Args, typename Char = char_t<S>>
+inline int fprintf(std::basic_ostream<Char>& os, const S& format_str,
const Args&... args) {
- internal::check_format_string<Args...>(format_str);
- typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
- typedef typename basic_printf_context_t<buffer>::type context;
+ using context = typename basic_printf_context_t<internal::buffer<Char>>::type;
format_arg_store<context, Args...> as{args...};
return vfprintf(os, to_string_view(format_str),
basic_format_args<context>(as));
diff --git a/src/third_party/fmt/dist/include/fmt/ranges.h b/src/third_party/fmt/dist/include/fmt/ranges.h
index 646d63f926b..9128f25a195 100644
--- a/src/third_party/fmt/dist/include/fmt/ranges.h
+++ b/src/third_party/fmt/dist/include/fmt/ranges.h
@@ -82,7 +82,7 @@ template <typename T> class is_like_std_string {
public:
static FMT_CONSTEXPR_DECL const bool value =
- !std::is_void<decltype(check<T>(FMT_NULL))>::value;
+ is_string<T>::value || !std::is_void<decltype(check<T>(nullptr))>::value;
};
template <typename Char>
@@ -95,25 +95,24 @@ template <typename T, typename _ = void> struct is_range_ : std::false_type {};
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
template <typename T>
struct is_range_<
- T, typename std::conditional<
- false,
- conditional_helper<decltype(internal::declval<T>().begin()),
- decltype(internal::declval<T>().end())>,
- void>::type> : std::true_type {};
+ T, conditional_t<false,
+ conditional_helper<decltype(std::declval<T>().begin()),
+ decltype(std::declval<T>().end())>,
+ void>> : std::true_type {};
#endif
/// tuple_size and tuple_element check.
template <typename T> class is_tuple_like_ {
template <typename U>
- static auto check(U* p) -> decltype(
- std::tuple_size<U>::value,
- (void)internal::declval<typename std::tuple_element<0, U>::type>(),
- int());
+ static auto check(U* p)
+ -> decltype(std::tuple_size<U>::value,
+ (void)std::declval<typename std::tuple_element<0, U>::type>(),
+ int());
template <typename> static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
- !std::is_void<decltype(check<T>(FMT_NULL))>::value;
+ !std::is_void<decltype(check<T>(nullptr))>::value;
};
// Check for integer_sequence
@@ -195,9 +194,7 @@ template <typename T> struct is_tuple_like {
};
template <typename TupleT, typename Char>
-struct formatter<
- TupleT, Char,
- typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> {
+struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
private:
// C++11 generic lambda for format()
template <typename FormatContext> struct format_each {
@@ -251,8 +248,7 @@ template <typename T> struct is_range {
};
template <typename RangeT, typename Char>
-struct formatter<RangeT, Char,
- typename std::enable_if<fmt::is_range<RangeT>::value>::type> {
+struct formatter<RangeT, Char, enable_if_t<fmt::is_range<RangeT>::value>> {
formatting_range<Char> formatting;
template <typename ParseContext>
diff --git a/src/third_party/fmt/dist/include/fmt/time.h b/src/third_party/fmt/dist/include/fmt/time.h
deleted file mode 100644
index 840c8cf766e..00000000000
--- a/src/third_party/fmt/dist/include/fmt/time.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Formatting library for C++ - time formatting
-//
-// Copyright (c) 2012 - present, Victor Zverovich
-// All rights reserved.
-//
-// For the license information refer to format.h.
-
-#ifndef FMT_TIME_H_
-#define FMT_TIME_H_
-
-#include "chrono.h"
-
-#warning fmt/time.h is deprecated, use fmt/chrono.h instead
-
-#endif // FMT_TIME_H_
diff --git a/src/third_party/fmt/dist/src/format.cc b/src/third_party/fmt/dist/src/format.cc
index 585ab6c1d20..b60b7e4fa0e 100644
--- a/src/third_party/fmt/dist/src/format.cc
+++ b/src/third_party/fmt/dist/src/format.cc
@@ -8,11 +8,11 @@
#include "fmt/format-inl.h"
FMT_BEGIN_NAMESPACE
-template struct internal::basic_data<void>;
+template struct FMT_API internal::basic_data<void>;
-// Workaround a bug in MSVC2013 that prevents instantiation of grisu2_format.
-bool (*instantiate_grisu2_format)(double, internal::buffer&, int, bool,
- int&) = internal::grisu2_format;
+// Workaround a bug in MSVC2013 that prevents instantiation of grisu_format.
+bool (*instantiate_grisu_format)(double, internal::buffer<char>&, int, unsigned,
+ int&) = internal::grisu_format;
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
template FMT_API internal::locale_ref::locale_ref(const std::locale& loc);
@@ -23,49 +23,33 @@ template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
template FMT_API char internal::thousands_sep_impl(locale_ref);
-template FMT_API void internal::basic_buffer<char>::append(const char*,
- const char*);
+template FMT_API void internal::buffer<char>::append(const char*, const char*);
template FMT_API void internal::arg_map<format_context>::init(
const basic_format_args<format_context>& args);
-template FMT_API int internal::char_traits<char>::format_float(char*,
- std::size_t,
- const char*, int,
- double);
-
-template FMT_API int internal::char_traits<char>::format_float(char*,
- std::size_t,
- const char*, int,
- long double);
-
template FMT_API std::string internal::vformat<char>(
string_view, basic_format_args<format_context>);
template FMT_API format_context::iterator internal::vformat_to(
- internal::buffer&, string_view, basic_format_args<format_context>);
+ internal::buffer<char>&, string_view, basic_format_args<format_context>);
-template FMT_API void internal::sprintf_format(double, internal::buffer&,
+template FMT_API void internal::sprintf_format(double, internal::buffer<char>&,
core_format_specs);
-template FMT_API void internal::sprintf_format(long double, internal::buffer&,
+template FMT_API void internal::sprintf_format(long double,
+ internal::buffer<char>&,
core_format_specs);
// Explicit instantiations for wchar_t.
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
-template FMT_API void internal::basic_buffer<wchar_t>::append(const wchar_t*,
- const wchar_t*);
+template FMT_API void internal::buffer<wchar_t>::append(const wchar_t*,
+ const wchar_t*);
template FMT_API void internal::arg_map<wformat_context>::init(
const basic_format_args<wformat_context>&);
-template FMT_API int internal::char_traits<wchar_t>::format_float(
- wchar_t*, std::size_t, const wchar_t*, int, double);
-
-template FMT_API int internal::char_traits<wchar_t>::format_float(
- wchar_t*, std::size_t, const wchar_t*, int, long double);
-
template FMT_API std::wstring internal::vformat<wchar_t>(
wstring_view, basic_format_args<wformat_context>);
FMT_END_NAMESPACE
diff --git a/src/third_party/fmt/dist/src/posix.cc b/src/third_party/fmt/dist/src/posix.cc
index fd6eb1695df..69c27819d2b 100644
--- a/src/third_party/fmt/dist/src/posix.cc
+++ b/src/third_party/fmt/dist/src/posix.cc
@@ -73,7 +73,7 @@ buffered_file::~buffered_file() FMT_NOEXCEPT {
buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
- FMT_NULL);
+ nullptr);
if (!file_)
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
}
@@ -81,7 +81,7 @@ buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
void buffered_file::close() {
if (!file_) return;
int result = FMT_SYSTEM(fclose(file_));
- file_ = FMT_NULL;
+ file_ = nullptr;
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
}
diff --git a/src/third_party/fmt/scripts/import.sh b/src/third_party/fmt/scripts/import.sh
index 5d7116a910b..dc17b20beec 100755
--- a/src/third_party/fmt/scripts/import.sh
+++ b/src/third_party/fmt/scripts/import.sh
@@ -4,7 +4,7 @@
set -vxeuo pipefail
FMT_GIT_URL="https://github.com/mongodb-forks/fmt.git"
-FMT_GIT_REV=018d8b57f6ff76fc5bb5abaa243ff3f805bf297f # 2019-03-30
+FMT_GIT_REV=e37ee419c6c31825ee56b06590dec0b2561ab310 # 2019-06-24
FMT_GIT_DIR=$(mktemp -d /tmp/import-fmt.XXXXXX)
trap "rm -rf $FMT_GIT_DIR" EXIT