diff options
author | Billy Donahue <billy.donahue@mongodb.com> | 2019-06-28 15:56:59 -0400 |
---|---|---|
committer | Billy Donahue <billy.donahue@mongodb.com> | 2019-07-02 12:44:07 -0400 |
commit | ac0e818b74ecdfb02bab1ea73e4f894b634184bd (patch) | |
tree | 6d5391a61001e9579a0981f2aa1c8c433b38d050 /src/third_party | |
parent | 2bc1da6a3d84551d7ae035320706621fabe341ae (diff) | |
download | mongo-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')
-rw-r--r-- | src/third_party/fmt/dist/include/fmt/chrono.h | 226 | ||||
-rw-r--r-- | src/third_party/fmt/dist/include/fmt/color.h | 48 | ||||
-rw-r--r-- | src/third_party/fmt/dist/include/fmt/core.h | 1055 | ||||
-rw-r--r-- | src/third_party/fmt/dist/include/fmt/format-inl.h | 231 | ||||
-rw-r--r-- | src/third_party/fmt/dist/include/fmt/format.h | 866 | ||||
-rw-r--r-- | src/third_party/fmt/dist/include/fmt/locale.h | 45 | ||||
-rw-r--r-- | src/third_party/fmt/dist/include/fmt/ostream.h | 44 | ||||
-rw-r--r-- | src/third_party/fmt/dist/include/fmt/posix.h | 16 | ||||
-rw-r--r-- | src/third_party/fmt/dist/include/fmt/prepare.h | 95 | ||||
-rw-r--r-- | src/third_party/fmt/dist/include/fmt/printf.h | 142 | ||||
-rw-r--r-- | src/third_party/fmt/dist/include/fmt/ranges.h | 28 | ||||
-rw-r--r-- | src/third_party/fmt/dist/include/fmt/time.h | 15 | ||||
-rw-r--r-- | src/third_party/fmt/dist/src/format.cc | 38 | ||||
-rw-r--r-- | src/third_party/fmt/dist/src/posix.cc | 4 | ||||
-rwxr-xr-x | src/third_party/fmt/scripts/import.sh | 2 |
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 |