diff options
author | Bart Ribbers <bribbers@disroot.org> | 2021-08-18 13:53:39 +0200 |
---|---|---|
committer | Bart Ribbers <bribbers@disroot.org> | 2021-08-18 11:56:18 +0000 |
commit | 6c77b42e86554e06d17b5e20732875cdd3591828 (patch) | |
tree | 1b14556f9fed54ef929f41e254122b1cc3e7dd36 | |
parent | 029369dd2f9e9882364109a720b26b95fb8583ac (diff) | |
download | aports-6c77b42e86554e06d17b5e20732875cdd3591828.tar.gz aports-6c77b42e86554e06d17b5e20732875cdd3591828.tar.bz2 aports-6c77b42e86554e06d17b5e20732875cdd3591828.tar.xz |
community/spdlog: upgrade to 1.9.2
-rw-r--r-- | community/spdlog/0001-Update-fmt-version-8.0.patch | 13802 | ||||
-rw-r--r-- | community/spdlog/APKBUILD | 11 |
2 files changed, 4 insertions, 13809 deletions
diff --git a/community/spdlog/0001-Update-fmt-version-8.0.patch b/community/spdlog/0001-Update-fmt-version-8.0.patch deleted file mode 100644 index f4b49126e2f..00000000000 --- a/community/spdlog/0001-Update-fmt-version-8.0.patch +++ /dev/null @@ -1,13802 +0,0 @@ -From 8bf718671a9eac5517c27a5ffe72089b7f426d8c Mon Sep 17 00:00:00 2001 -From: gabime <gmelman1@gmail.com> -Date: Thu, 24 Jun 2021 13:22:02 +0300 -Subject: [PATCH] Update fmt version 8.0 - ---- - include/spdlog/common-inl.h | 2 +- - include/spdlog/fmt/bundled/LICENSE.rst | 27 - - include/spdlog/fmt/bundled/chrono.h | 420 ++- - include/spdlog/fmt/bundled/color.h | 120 +- - include/spdlog/fmt/bundled/compile.h | 784 +++-- - include/spdlog/fmt/bundled/core.h | 2294 +++++++++----- - include/spdlog/fmt/bundled/format-inl.h | 2044 ++++++------- - include/spdlog/fmt/bundled/format.h | 3643 ++++++++--------------- - include/spdlog/fmt/bundled/locale.h | 66 +- - include/spdlog/fmt/bundled/os.h | 187 +- - include/spdlog/fmt/bundled/ostream.h | 4 + - include/spdlog/fmt/bundled/posix.h | 2 - - include/spdlog/fmt/bundled/printf.h | 469 ++- - include/spdlog/fmt/bundled/ranges.h | 309 +- - src/fmt.cpp | 100 +- - 15 files changed, 5039 insertions(+), 5432 deletions(-) - delete mode 100644 include/spdlog/fmt/bundled/LICENSE.rst - delete mode 100644 include/spdlog/fmt/bundled/posix.h - -diff --git a/include/spdlog/common-inl.h b/include/spdlog/common-inl.h -index c3e99222..5fa4e5d9 100644 ---- a/include/spdlog/common-inl.h -+++ b/include/spdlog/common-inl.h -@@ -56,7 +56,7 @@ SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg) - SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) - { - memory_buf_t outbuf; -- fmt::format_system_error(outbuf, last_errno, msg); -+ fmt::format_system_error(outbuf, last_errno, msg.c_str()); - msg_ = fmt::to_string(outbuf); - } - -diff --git a/include/spdlog/fmt/bundled/LICENSE.rst b/include/spdlog/fmt/bundled/LICENSE.rst -deleted file mode 100644 -index f0ec3db4..00000000 ---- a/include/spdlog/fmt/bundled/LICENSE.rst -+++ /dev/null -@@ -1,27 +0,0 @@ --Copyright (c) 2012 - present, Victor Zverovich -- --Permission is hereby granted, free of charge, to any person obtaining --a copy of this software and associated documentation files (the --"Software"), to deal in the Software without restriction, including --without limitation the rights to use, copy, modify, merge, publish, --distribute, sublicense, and/or sell copies of the Software, and to --permit persons to whom the Software is furnished to do so, subject to --the following conditions: -- --The above copyright notice and this permission notice shall be --included in all copies or substantial portions of the Software. -- --THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, --EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF --MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND --NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE --LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION --OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION --WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -- ----- Optional exception to the license --- -- --As an exception, if, as a result of your compiling your source code, portions --of this Software are embedded into a machine-executable object form of such --source code, you may redistribute such embedded portions in such object form --without including the above copyright and permission notices. -diff --git a/include/spdlog/fmt/bundled/chrono.h b/include/spdlog/fmt/bundled/chrono.h -index 1a3b8d5e..c024fd71 100644 ---- a/include/spdlog/fmt/bundled/chrono.h -+++ b/include/spdlog/fmt/bundled/chrono.h -@@ -8,13 +8,13 @@ - #ifndef FMT_CHRONO_H_ - #define FMT_CHRONO_H_ - -+#include <algorithm> - #include <chrono> - #include <ctime> - #include <locale> - #include <sstream> - - #include "format.h" --#include "locale.h" - - FMT_BEGIN_NAMESPACE - -@@ -282,13 +282,89 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from, - #define FMT_NOMACRO - - namespace detail { -+template <typename T = void> struct null {}; - inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); } - inline null<> localtime_s(...) { return null<>(); } - inline null<> gmtime_r(...) { return null<>(); } - inline null<> gmtime_s(...) { return null<>(); } -+ -+inline auto do_write(const std::tm& time, const std::locale& loc, char format, -+ char modifier) -> std::string { -+ auto&& os = std::ostringstream(); -+ os.imbue(loc); -+ using iterator = std::ostreambuf_iterator<char>; -+ const auto& facet = std::use_facet<std::time_put<char, iterator>>(loc); -+ auto end = facet.put(os, os, ' ', &time, format, modifier); -+ if (end.failed()) FMT_THROW(format_error("failed to format time")); -+ auto str = os.str(); -+ if (!detail::is_utf8() || loc == std::locale::classic()) return str; -+ // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and -+ // gcc-4. -+#if FMT_MSC_VER != 0 || \ -+ (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI)) -+ // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5 -+ // and newer. -+ using code_unit = wchar_t; -+#else -+ using code_unit = char32_t; -+#endif -+ auto& f = std::use_facet<std::codecvt<code_unit, char, std::mbstate_t>>(loc); -+ auto mb = std::mbstate_t(); -+ const char* from_next = nullptr; -+ code_unit* to_next = nullptr; -+ constexpr size_t buf_size = 32; -+ code_unit buf[buf_size] = {}; -+ auto result = f.in(mb, str.data(), str.data() + str.size(), from_next, buf, -+ buf + buf_size, to_next); -+ if (result != std::codecvt_base::ok) -+ FMT_THROW(format_error("failed to format time")); -+ str.clear(); -+ for (code_unit* p = buf; p != to_next; ++p) { -+ uint32_t c = static_cast<uint32_t>(*p); -+ if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) { -+ // surrogate pair -+ ++p; -+ if (p == to_next || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) { -+ FMT_THROW(format_error("failed to format time")); -+ } -+ c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00; -+ } -+ if (c < 0x80) { -+ str.push_back(static_cast<char>(c)); -+ } else if (c < 0x800) { -+ str.push_back(static_cast<char>(0xc0 | (c >> 6))); -+ str.push_back(static_cast<char>(0x80 | (c & 0x3f))); -+ } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) { -+ str.push_back(static_cast<char>(0xe0 | (c >> 12))); -+ str.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6))); -+ str.push_back(static_cast<char>(0x80 | (c & 0x3f))); -+ } else if (c >= 0x10000 && c <= 0x10ffff) { -+ str.push_back(static_cast<char>(0xf0 | (c >> 18))); -+ str.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12))); -+ str.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6))); -+ str.push_back(static_cast<char>(0x80 | (c & 0x3f))); -+ } else { -+ FMT_THROW(format_error("failed to format time")); -+ } -+ } -+ return str; -+} -+ -+template <typename OutputIt> -+auto write(OutputIt out, const std::tm& time, const std::locale& loc, -+ char format, char modifier = 0) -> OutputIt { -+ auto str = do_write(time, loc, format, modifier); -+ return std::copy(str.begin(), str.end(), out); -+} - } // namespace detail - --// Thread-safe replacement for std::localtime -+FMT_MODULE_EXPORT_BEGIN -+ -+/** -+ Converts given time since epoch as ``std::time_t`` value into calendar time, -+ expressed in local time. Unlike ``std::localtime``, this function is -+ thread-safe on most platforms. -+ */ - inline std::tm localtime(std::time_t time) { - struct dispatcher { - std::time_t time_; -@@ -330,7 +406,11 @@ inline std::tm localtime( - return localtime(std::chrono::system_clock::to_time_t(time_point)); - } - --// Thread-safe replacement for std::gmtime -+/** -+ Converts given time since epoch as ``std::time_t`` value into calendar time, -+ expressed in Coordinated Universal Time (UTC). Unlike ``std::gmtime``, this -+ function is thread-safe on most platforms. -+ */ - inline std::tm gmtime(std::time_t time) { - struct dispatcher { - std::time_t time_; -@@ -371,44 +451,84 @@ inline std::tm gmtime( - return gmtime(std::chrono::system_clock::to_time_t(time_point)); - } - --namespace detail { -+FMT_BEGIN_DETAIL_NAMESPACE -+ - inline size_t strftime(char* str, size_t count, const char* format, - const std::tm* time) { -- return std::strftime(str, count, format, time); -+ // Assign to a pointer to suppress GCCs -Wformat-nonliteral -+ // First assign the nullptr to suppress -Wsuggest-attribute=format -+ std::size_t (*strftime)(char*, std::size_t, const char*, const std::tm*) = -+ nullptr; -+ strftime = std::strftime; -+ return strftime(str, count, format, time); - } - - inline size_t strftime(wchar_t* str, size_t count, const wchar_t* format, - const std::tm* time) { -- return std::wcsftime(str, count, format, time); -+ // See above -+ std::size_t (*wcsftime)(wchar_t*, std::size_t, const wchar_t*, -+ const std::tm*) = nullptr; -+ wcsftime = std::wcsftime; -+ return wcsftime(str, count, format, time); - } --} // namespace detail - --template <typename Char> --struct formatter<std::chrono::time_point<std::chrono::system_clock>, Char> -- : formatter<std::tm, Char> { -+FMT_END_DETAIL_NAMESPACE -+ -+template <typename Char, typename Duration> -+struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>, -+ Char> : formatter<std::tm, Char> { -+ FMT_CONSTEXPR formatter() { -+ this->specs = {default_specs, sizeof(default_specs) / sizeof(Char)}; -+ } -+ -+ template <typename ParseContext> -+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { -+ auto it = ctx.begin(); -+ if (it != ctx.end() && *it == ':') ++it; -+ auto end = it; -+ while (end != ctx.end() && *end != '}') ++end; -+ if (end != it) this->specs = {it, detail::to_unsigned(end - it)}; -+ return end; -+ } -+ - template <typename FormatContext> - auto format(std::chrono::time_point<std::chrono::system_clock> val, - FormatContext& ctx) -> decltype(ctx.out()) { - std::tm time = localtime(val); - return formatter<std::tm, Char>::format(time, ctx); - } -+ -+ static constexpr Char default_specs[] = {'%', 'Y', '-', '%', 'm', '-', -+ '%', 'd', ' ', '%', 'H', ':', -+ '%', 'M', ':', '%', 'S'}; - }; - -+template <typename Char, typename Duration> -+constexpr Char -+ formatter<std::chrono::time_point<std::chrono::system_clock, Duration>, -+ Char>::default_specs[]; -+ - template <typename Char> struct formatter<std::tm, Char> { - template <typename ParseContext> -- auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { -+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - auto it = ctx.begin(); - if (it != ctx.end() && *it == ':') ++it; - auto end = it; - while (end != ctx.end() && *end != '}') ++end; -- tm_format.reserve(detail::to_unsigned(end - it + 1)); -- tm_format.append(it, end); -- tm_format.push_back('\0'); -+ specs = {it, detail::to_unsigned(end - it)}; - return end; - } - - template <typename FormatContext> -- auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) { -+ auto format(const std::tm& tm, FormatContext& ctx) const -+ -> decltype(ctx.out()) { -+ basic_memory_buffer<Char> tm_format; -+ tm_format.append(specs.begin(), specs.end()); -+ // By appending an extra space we can distinguish an empty result that -+ // indicates insufficient buffer size from a guaranteed non-empty result -+ // https://github.com/fmtlib/fmt/issues/2238 -+ tm_format.push_back(' '); -+ tm_format.push_back('\0'); - basic_memory_buffer<Char> buf; - size_t start = buf.size(); - for (;;) { -@@ -418,49 +538,40 @@ template <typename Char> struct formatter<std::tm, Char> { - buf.resize(start + count); - break; - } -- if (size >= tm_format.size() * 256) { -- // If the buffer is 256 times larger than the format string, assume -- // that `strftime` gives an empty result. There doesn't seem to be a -- // better way to distinguish the two cases: -- // https://github.com/fmtlib/fmt/issues/367 -- break; -- } - const size_t MIN_GROWTH = 10; - buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); - } -- return std::copy(buf.begin(), buf.end(), ctx.out()); -+ // Remove the extra space. -+ return std::copy(buf.begin(), buf.end() - 1, ctx.out()); - } - -- basic_memory_buffer<Char> tm_format; -+ basic_string_view<Char> specs; - }; - --namespace detail { --template <typename Period> FMT_CONSTEXPR const char* get_units() { -+FMT_BEGIN_DETAIL_NAMESPACE -+ -+template <typename Period> FMT_CONSTEXPR inline const char* get_units() { -+ if (std::is_same<Period, std::atto>::value) return "as"; -+ if (std::is_same<Period, std::femto>::value) return "fs"; -+ if (std::is_same<Period, std::pico>::value) return "ps"; -+ if (std::is_same<Period, std::nano>::value) return "ns"; -+ if (std::is_same<Period, std::micro>::value) return "µs"; -+ if (std::is_same<Period, std::milli>::value) return "ms"; -+ if (std::is_same<Period, std::centi>::value) return "cs"; -+ if (std::is_same<Period, std::deci>::value) return "ds"; -+ if (std::is_same<Period, std::ratio<1>>::value) return "s"; -+ if (std::is_same<Period, std::deca>::value) return "das"; -+ if (std::is_same<Period, std::hecto>::value) return "hs"; -+ if (std::is_same<Period, std::kilo>::value) return "ks"; -+ if (std::is_same<Period, std::mega>::value) return "Ms"; -+ if (std::is_same<Period, std::giga>::value) return "Gs"; -+ if (std::is_same<Period, std::tera>::value) return "Ts"; -+ if (std::is_same<Period, std::peta>::value) return "Ps"; -+ if (std::is_same<Period, std::exa>::value) return "Es"; -+ if (std::is_same<Period, std::ratio<60>>::value) return "m"; -+ if (std::is_same<Period, std::ratio<3600>>::value) return "h"; - return nullptr; - } --template <> FMT_CONSTEXPR const char* get_units<std::atto>() { return "as"; } --template <> FMT_CONSTEXPR const char* get_units<std::femto>() { return "fs"; } --template <> FMT_CONSTEXPR const char* get_units<std::pico>() { return "ps"; } --template <> FMT_CONSTEXPR const char* get_units<std::nano>() { return "ns"; } --template <> FMT_CONSTEXPR const char* get_units<std::micro>() { return "µs"; } --template <> FMT_CONSTEXPR const char* get_units<std::milli>() { return "ms"; } --template <> FMT_CONSTEXPR const char* get_units<std::centi>() { return "cs"; } --template <> FMT_CONSTEXPR const char* get_units<std::deci>() { return "ds"; } --template <> FMT_CONSTEXPR const char* get_units<std::ratio<1>>() { return "s"; } --template <> FMT_CONSTEXPR const char* get_units<std::deca>() { return "das"; } --template <> FMT_CONSTEXPR const char* get_units<std::hecto>() { return "hs"; } --template <> FMT_CONSTEXPR const char* get_units<std::kilo>() { return "ks"; } --template <> FMT_CONSTEXPR const char* get_units<std::mega>() { return "Ms"; } --template <> FMT_CONSTEXPR const char* get_units<std::giga>() { return "Gs"; } --template <> FMT_CONSTEXPR const char* get_units<std::tera>() { return "Ts"; } --template <> FMT_CONSTEXPR const char* get_units<std::peta>() { return "Ps"; } --template <> FMT_CONSTEXPR const char* get_units<std::exa>() { return "Es"; } --template <> FMT_CONSTEXPR const char* get_units<std::ratio<60>>() { -- return "m"; --} --template <> FMT_CONSTEXPR const char* get_units<std::ratio<3600>>() { -- return "h"; --} - - enum class numeric_system { - standard, -@@ -626,33 +737,50 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, - return ptr; - } - --struct chrono_format_checker { -- FMT_NORETURN void report_no_date() { FMT_THROW(format_error("no date")); } -- -- template <typename Char> void on_text(const Char*, const Char*) {} -- 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) {} -- 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() {} -- FMT_NORETURN void on_utc_offset() { report_no_date(); } -- FMT_NORETURN void on_tz_name() { report_no_date(); } -+template <typename Derived> struct null_chrono_spec_handler { -+ FMT_CONSTEXPR void unsupported() { -+ static_cast<Derived*>(this)->unsupported(); -+ } -+ FMT_CONSTEXPR void on_abbr_weekday() { unsupported(); } -+ FMT_CONSTEXPR void on_full_weekday() { unsupported(); } -+ FMT_CONSTEXPR void on_dec0_weekday(numeric_system) { unsupported(); } -+ FMT_CONSTEXPR void on_dec1_weekday(numeric_system) { unsupported(); } -+ FMT_CONSTEXPR void on_abbr_month() { unsupported(); } -+ FMT_CONSTEXPR void on_full_month() { unsupported(); } -+ FMT_CONSTEXPR void on_24_hour(numeric_system) { unsupported(); } -+ FMT_CONSTEXPR void on_12_hour(numeric_system) { unsupported(); } -+ FMT_CONSTEXPR void on_minute(numeric_system) { unsupported(); } -+ FMT_CONSTEXPR void on_second(numeric_system) { unsupported(); } -+ FMT_CONSTEXPR void on_datetime(numeric_system) { unsupported(); } -+ FMT_CONSTEXPR void on_loc_date(numeric_system) { unsupported(); } -+ FMT_CONSTEXPR void on_loc_time(numeric_system) { unsupported(); } -+ FMT_CONSTEXPR void on_us_date() { unsupported(); } -+ FMT_CONSTEXPR void on_iso_date() { unsupported(); } -+ FMT_CONSTEXPR void on_12_hour_time() { unsupported(); } -+ FMT_CONSTEXPR void on_24_hour_time() { unsupported(); } -+ FMT_CONSTEXPR void on_iso_time() { unsupported(); } -+ FMT_CONSTEXPR void on_am_pm() { unsupported(); } -+ FMT_CONSTEXPR void on_duration_value() { unsupported(); } -+ FMT_CONSTEXPR void on_duration_unit() { unsupported(); } -+ FMT_CONSTEXPR void on_utc_offset() { unsupported(); } -+ FMT_CONSTEXPR void on_tz_name() { unsupported(); } -+}; -+ -+struct chrono_format_checker : null_chrono_spec_handler<chrono_format_checker> { -+ FMT_NORETURN void unsupported() { FMT_THROW(format_error("no date")); } -+ -+ template <typename Char> -+ FMT_CONSTEXPR void on_text(const Char*, const Char*) {} -+ FMT_CONSTEXPR void on_24_hour(numeric_system) {} -+ FMT_CONSTEXPR void on_12_hour(numeric_system) {} -+ FMT_CONSTEXPR void on_minute(numeric_system) {} -+ FMT_CONSTEXPR void on_second(numeric_system) {} -+ FMT_CONSTEXPR void on_12_hour_time() {} -+ FMT_CONSTEXPR void on_24_hour_time() {} -+ FMT_CONSTEXPR void on_iso_time() {} -+ FMT_CONSTEXPR void on_am_pm() {} -+ FMT_CONSTEXPR void on_duration_value() {} -+ FMT_CONSTEXPR void on_duration_unit() {} - }; - - template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> -@@ -676,7 +804,8 @@ inline bool isfinite(T value) { - // Converts 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"); -+ FMT_ASSERT(value >= 0 && to_unsigned(value) <= to_unsigned(upper), -+ "invalid value"); - (void)upper; - return static_cast<int>(value); - } -@@ -754,15 +883,21 @@ inline std::chrono::duration<Rep, std::milli> get_milliseconds( - return std::chrono::duration<Rep, std::milli>(static_cast<Rep>(ms)); - } - --template <typename Char, typename Rep, typename OutputIt> -+template <typename Char, typename Rep, typename OutputIt, -+ FMT_ENABLE_IF(std::is_integral<Rep>::value)> -+OutputIt format_duration_value(OutputIt out, Rep val, int) { -+ return write<Char>(out, val); -+} -+ -+template <typename Char, typename Rep, typename OutputIt, -+ FMT_ENABLE_IF(std::is_floating_point<Rep>::value)> - OutputIt format_duration_value(OutputIt out, Rep val, int precision) { -- const Char pr_f[] = {'{', ':', '.', '{', '}', 'f', '}', 0}; -- if (precision >= 0) return format_to(out, pr_f, val, precision); -- const Char fp_f[] = {'{', ':', 'g', '}', 0}; -- const Char format[] = {'{', '}', 0}; -- return format_to(out, std::is_floating_point<Rep>::value ? fp_f : format, -- val); -+ auto specs = basic_format_specs<Char>(); -+ specs.precision = precision; -+ specs.type = precision > 0 ? 'f' : 'g'; -+ return write<Char>(out, val, specs); - } -+ - template <typename Char, typename OutputIt> - OutputIt copy_unit(string_view unit, OutputIt out, Char) { - return std::copy(unit.begin(), unit.end(), out); -@@ -780,10 +915,15 @@ template <typename Char, typename Period, typename OutputIt> - OutputIt format_duration_unit(OutputIt out) { - if (const char* unit = get_units<Period>()) - return copy_unit(string_view(unit), out, Char()); -- const Char num_f[] = {'[', '{', '}', ']', 's', 0}; -- if (const_check(Period::den == 1)) return format_to(out, num_f, Period::num); -- const Char num_def_f[] = {'[', '{', '}', '/', '{', '}', ']', 's', 0}; -- return format_to(out, num_def_f, Period::num, Period::den); -+ *out++ = '['; -+ out = write<Char>(out, Period::num); -+ if (const_check(Period::den != 1)) { -+ *out++ = '/'; -+ out = write<Char>(out, Period::den); -+ } -+ *out++ = ']'; -+ *out++ = 's'; -+ return out; - } - - template <typename FormatContext, typename OutputIt, typename Rep, -@@ -792,6 +932,7 @@ struct chrono_formatter { - FormatContext& context; - OutputIt out; - int precision; -+ bool localized = false; - // rep is unsigned to avoid overflow. - using rep = - conditional_t<std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int), -@@ -886,13 +1027,9 @@ struct chrono_formatter { - - void format_localized(const tm& time, char format, char modifier = 0) { - 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; -- os.imbue(locale); -- facet.put(os, os, ' ', &time, format, modifier); -- auto str = os.str(); -- std::copy(str.begin(), str.end(), out); -+ const auto& loc = localized ? context.locale().template get<std::locale>() -+ : std::locale::classic(); -+ out = detail::write(out, time, loc, format, modifier); - } - - void on_text(const char_type* begin, const char_type* end) { -@@ -1005,17 +1142,59 @@ struct chrono_formatter { - out = format_duration_unit<char_type, Period>(out); - } - }; --} // namespace detail -+ -+FMT_END_DETAIL_NAMESPACE -+ -+#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907 -+using weekday = std::chrono::weekday; -+#else -+// A fallback version of weekday. -+class weekday { -+ private: -+ unsigned char value; -+ -+ public: -+ weekday() = default; -+ explicit constexpr weekday(unsigned wd) noexcept -+ : value(static_cast<unsigned char>(wd != 7 ? wd : 0)) {} -+ constexpr unsigned c_encoding() const noexcept { return value; } -+}; -+#endif -+ -+// A rudimentary weekday formatter. -+template <> struct formatter<weekday> { -+ private: -+ bool localized = false; -+ -+ public: -+ FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { -+ auto begin = ctx.begin(), end = ctx.end(); -+ if (begin != end && *begin == 'L') { -+ ++begin; -+ localized = true; -+ } -+ return begin; -+ } -+ -+ auto format(weekday wd, format_context& ctx) -> decltype(ctx.out()) { -+ auto time = std::tm(); -+ time.tm_wday = static_cast<int>(wd.c_encoding()); -+ const auto& loc = localized ? ctx.locale().template get<std::locale>() -+ : std::locale::classic(); -+ return detail::write(ctx.out(), time, loc, 'a'); -+ } -+}; - - template <typename Rep, typename Period, typename Char> - struct formatter<std::chrono::duration<Rep, Period>, Char> { - private: - basic_format_specs<Char> specs; -- int precision; -+ int precision = -1; - using arg_ref_type = detail::arg_ref<Char>; - arg_ref_type width_ref; - arg_ref_type precision_ref; -- mutable basic_string_view<Char> format_str; -+ bool localized = false; -+ basic_string_view<Char> format_str; - using duration = std::chrono::duration<Rep, Period>; - - struct spec_handler { -@@ -1038,17 +1217,21 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> { - } - - void on_error(const char* msg) { FMT_THROW(format_error(msg)); } -- void on_fill(basic_string_view<Char> fill) { f.specs.fill = fill; } -- void on_align(align_t align) { f.specs.align = align; } -- void on_width(int width) { f.specs.width = width; } -- void on_precision(int _precision) { f.precision = _precision; } -- void end_precision() {} -+ FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) { -+ f.specs.fill = fill; -+ } -+ FMT_CONSTEXPR void on_align(align_t align) { f.specs.align = align; } -+ FMT_CONSTEXPR void on_width(int width) { f.specs.width = width; } -+ FMT_CONSTEXPR void on_precision(int _precision) { -+ f.precision = _precision; -+ } -+ FMT_CONSTEXPR void end_precision() {} - -- template <typename Id> void on_dynamic_width(Id arg_id) { -+ template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { - f.width_ref = make_arg_ref(arg_id); - } - -- template <typename Id> void on_dynamic_precision(Id arg_id) { -+ template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { - f.precision_ref = make_arg_ref(arg_id); - } - }; -@@ -1073,13 +1256,15 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> { - else - handler.on_error("precision not allowed for this argument type"); - } -+ if (begin != end && *begin == 'L') { -+ ++begin; -+ localized = true; -+ } - end = parse_chrono_format(begin, end, detail::chrono_format_checker()); - return {begin, end}; - } - - public: -- formatter() : precision(-1) {} -- - FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx) - -> decltype(ctx.begin()) { - auto range = do_parse(ctx); -@@ -1089,30 +1274,35 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> { - } - - template <typename FormatContext> -- auto format(const duration& d, FormatContext& ctx) -> decltype(ctx.out()) { -+ auto format(const duration& d, FormatContext& ctx) const -+ -> decltype(ctx.out()) { -+ auto specs_copy = specs; -+ auto precision_copy = precision; - auto begin = format_str.begin(), end = format_str.end(); - // As a possible future optimization, we could avoid extra copying if width - // is not specified. - basic_memory_buffer<Char> buf; - auto out = std::back_inserter(buf); -- detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref, -- ctx); -- detail::handle_dynamic_spec<detail::precision_checker>(precision, -+ detail::handle_dynamic_spec<detail::width_checker>(specs_copy.width, -+ width_ref, ctx); -+ detail::handle_dynamic_spec<detail::precision_checker>(precision_copy, - precision_ref, ctx); - if (begin == end || *begin == '}') { -- out = detail::format_duration_value<Char>(out, d.count(), precision); -+ out = detail::format_duration_value<Char>(out, d.count(), precision_copy); - detail::format_duration_unit<Char, Period>(out); - } else { - detail::chrono_formatter<FormatContext, decltype(out), Rep, Period> f( - ctx, out, d); -- f.precision = precision; -- parse_chrono_format(begin, end, f); -+ f.precision = precision_copy; -+ f.localized = localized; -+ detail::parse_chrono_format(begin, end, f); - } - return detail::write( -- ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs); -+ ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs_copy); - } - }; - -+FMT_MODULE_EXPORT_END - FMT_END_NAMESPACE - - #endif // FMT_CHRONO_H_ -diff --git a/include/spdlog/fmt/bundled/color.h b/include/spdlog/fmt/bundled/color.h -index 94e3419d..7fa5490e 100644 ---- a/include/spdlog/fmt/bundled/color.h -+++ b/include/spdlog/fmt/bundled/color.h -@@ -10,7 +10,15 @@ - - #include "format.h" - -+// __declspec(deprecated) is broken in some MSVC versions. -+#if FMT_MSC_VER -+# define FMT_DEPRECATED_NONMSVC -+#else -+# define FMT_DEPRECATED_NONMSVC FMT_DEPRECATED -+#endif -+ - FMT_BEGIN_NAMESPACE -+FMT_MODULE_EXPORT_BEGIN - - enum class color : uint32_t { - alice_blue = 0xF0F8FF, // rgb(240,248,255) -@@ -198,7 +206,7 @@ struct rgb { - uint8_t b; - }; - --namespace detail { -+FMT_BEGIN_DETAIL_NAMESPACE - - // color is a struct of either a rgb color or a terminal color. - struct color_type { -@@ -221,9 +229,10 @@ struct color_type { - uint32_t rgb_color; - } value; - }; --} // namespace detail - --// Experimental text formatting support. -+FMT_END_DETAIL_NAMESPACE -+ -+/** A text style consisting of foreground and background colors and emphasis. */ - class text_style { - public: - FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT -@@ -260,33 +269,14 @@ class text_style { - return lhs |= rhs; - } - -- FMT_CONSTEXPR text_style& operator&=(const text_style& rhs) { -- if (!set_foreground_color) { -- set_foreground_color = rhs.set_foreground_color; -- foreground_color = rhs.foreground_color; -- } else if (rhs.set_foreground_color) { -- if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) -- FMT_THROW(format_error("can't AND a terminal color")); -- foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color; -- } -- -- if (!set_background_color) { -- set_background_color = rhs.set_background_color; -- background_color = rhs.background_color; -- } else if (rhs.set_background_color) { -- if (!background_color.is_rgb || !rhs.background_color.is_rgb) -- FMT_THROW(format_error("can't AND a terminal color")); -- background_color.value.rgb_color &= rhs.background_color.value.rgb_color; -- } -- -- ems = static_cast<emphasis>(static_cast<uint8_t>(ems) & -- static_cast<uint8_t>(rhs.ems)); -- return *this; -+ FMT_DEPRECATED_NONMSVC FMT_CONSTEXPR text_style& operator&=( -+ const text_style& rhs) { -+ return and_assign(rhs); - } - -- friend FMT_CONSTEXPR text_style operator&(text_style lhs, -- const text_style& rhs) { -- return lhs &= rhs; -+ FMT_DEPRECATED_NONMSVC friend FMT_CONSTEXPR text_style -+ operator&(text_style lhs, const text_style& rhs) { -+ return lhs.and_assign(rhs); - } - - FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT { -@@ -326,8 +316,34 @@ class text_style { - } - } - -+ // DEPRECATED! -+ FMT_CONSTEXPR text_style& and_assign(const text_style& rhs) { -+ if (!set_foreground_color) { -+ set_foreground_color = rhs.set_foreground_color; -+ foreground_color = rhs.foreground_color; -+ } else if (rhs.set_foreground_color) { -+ if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) -+ FMT_THROW(format_error("can't AND a terminal color")); -+ foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color; -+ } -+ -+ if (!set_background_color) { -+ set_background_color = rhs.set_background_color; -+ background_color = rhs.background_color; -+ } else if (rhs.set_background_color) { -+ if (!background_color.is_rgb || !rhs.background_color.is_rgb) -+ FMT_THROW(format_error("can't AND a terminal color")); -+ background_color.value.rgb_color &= rhs.background_color.value.rgb_color; -+ } -+ -+ ems = static_cast<emphasis>(static_cast<uint8_t>(ems) & -+ static_cast<uint8_t>(rhs.ems)); -+ return *this; -+ } -+ - friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground) - FMT_NOEXCEPT; -+ - friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background) - FMT_NOEXCEPT; - -@@ -338,19 +354,22 @@ class text_style { - emphasis ems; - }; - --FMT_CONSTEXPR text_style fg(detail::color_type foreground) FMT_NOEXCEPT { -- return text_style(/*is_foreground=*/true, foreground); -+/** Creates a text style from the foreground (text) color. */ -+FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT { -+ return text_style(true, foreground); - } - --FMT_CONSTEXPR text_style bg(detail::color_type background) FMT_NOEXCEPT { -- return text_style(/*is_foreground=*/false, background); -+/** Creates a text style from the background color. */ -+FMT_CONSTEXPR inline text_style bg(detail::color_type background) FMT_NOEXCEPT { -+ return text_style(false, background); - } - --FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT { -+FMT_CONSTEXPR inline text_style operator|(emphasis lhs, -+ emphasis rhs) FMT_NOEXCEPT { - return text_style(lhs) | rhs; - } - --namespace detail { -+FMT_BEGIN_DETAIL_NAMESPACE - - template <typename Char> struct ansi_color_escape { - FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color, -@@ -358,7 +377,7 @@ template <typename Char> struct ansi_color_escape { - // If we have a terminal color, we need to output another escape code - // sequence. - if (!text_color.is_rgb) { -- bool is_background = esc == detail::data::background_color; -+ bool is_background = esc == string_view("\x1b[48;2;"); - uint32_t value = text_color.value.term_color; - // Background ASCII codes are the same as the foreground ones but with - // 10 more. -@@ -411,7 +430,7 @@ template <typename Char> struct ansi_color_escape { - FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; } - - FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; } -- FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT { -+ FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT { - return buffer + std::char_traits<Char>::length(buffer); - } - -@@ -430,13 +449,13 @@ template <typename Char> struct ansi_color_escape { - template <typename Char> - FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color( - detail::color_type foreground) FMT_NOEXCEPT { -- return ansi_color_escape<Char>(foreground, detail::data::foreground_color); -+ return ansi_color_escape<Char>(foreground, "\x1b[38;2;"); - } - - template <typename Char> - FMT_CONSTEXPR ansi_color_escape<Char> make_background_color( - detail::color_type background) FMT_NOEXCEPT { -- return ansi_color_escape<Char>(background, detail::data::background_color); -+ return ansi_color_escape<Char>(background, "\x1b[48;2;"); - } - - template <typename Char> -@@ -455,18 +474,17 @@ inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT { - } - - template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT { -- fputs(detail::data::reset_color, stream); -+ fputs("\x1b[0m", stream); - } - - template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT { -- fputs(detail::data::wreset_color, stream); -+ fputs(L"\x1b[0m", stream); - } - - template <typename Char> - inline void reset_color(buffer<Char>& buffer) FMT_NOEXCEPT { -- const char* begin = data::reset_color; -- const char* end = begin + sizeof(data::reset_color) - 1; -- buffer.append(begin, end); -+ auto reset_color = string_view("\x1b[0m"); -+ buffer.append(reset_color.begin(), reset_color.end()); - } - - template <typename Char> -@@ -492,7 +510,8 @@ void vformat_to(buffer<Char>& buf, const text_style& ts, - detail::vformat_to(buf, format_str, args); - if (has_style) detail::reset_color<Char>(buf); - } --} // namespace detail -+ -+FMT_END_DETAIL_NAMESPACE - - template <typename S, typename Char = char_t<S>> - void vprint(std::FILE* f, const text_style& ts, const S& format, -@@ -523,11 +542,15 @@ void print(std::FILE* f, const text_style& ts, const S& format_str, - } - - /** -+ \rst - Formats a string and prints it to stdout using ANSI escape sequences to - specify text formatting. -- Example: -+ -+ **Example**:: -+ - fmt::print(fmt::emphasis::bold | fg(fmt::color::red), - "Elapsed time: {0:.2f} seconds", 1.23); -+ \endrst - */ - template <typename S, typename... Args, - FMT_ENABLE_IF(detail::is_string<S>::value)> -@@ -559,8 +582,8 @@ inline std::basic_string<Char> vformat( - 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 vformat(ts, to_string_view(format_str), -- fmt::make_args_checked<Args...>(format_str, args...)); -+ return fmt::vformat(ts, to_string_view(format_str), -+ fmt::make_args_checked<Args...>(format_str, args...)); - } - - /** -@@ -571,7 +594,7 @@ template <typename OutputIt, typename Char, - OutputIt vformat_to( - OutputIt out, const text_style& ts, basic_string_view<Char> format_str, - basic_format_args<buffer_context<type_identity_t<Char>>> args) { -- decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out)); -+ auto&& buf = detail::get_buffer<Char>(out); - detail::vformat_to(buf, ts, format_str, args); - return detail::get_iterator(buf); - } -@@ -598,6 +621,7 @@ inline auto format_to(OutputIt out, const text_style& ts, const S& format_str, - fmt::make_args_checked<Args...>(format_str, args...)); - } - -+FMT_MODULE_EXPORT_END - FMT_END_NAMESPACE - - #endif // FMT_COLOR_H_ -diff --git a/include/spdlog/fmt/bundled/compile.h b/include/spdlog/fmt/bundled/compile.h -index 3a33b020..00000c92 100644 ---- a/include/spdlog/fmt/bundled/compile.h -+++ b/include/spdlog/fmt/bundled/compile.h -@@ -8,360 +8,176 @@ - #ifndef FMT_COMPILE_H_ - #define FMT_COMPILE_H_ - --#include <vector> -- - #include "format.h" - - FMT_BEGIN_NAMESPACE - namespace detail { - --// A compile-time string which is compiled into fast formatting code. --class compiled_string {}; -- --template <typename S> --struct is_compiled_string : std::is_base_of<compiled_string, S> {}; -- --/** -- \rst -- Converts a string literal *s* into a format string that will be parsed at -- compile time and converted into efficient formatting code. Requires C++17 -- ``constexpr if`` compiler support. -- -- **Example**:: -- -- // Converts 42 into std::string using the most efficient method and no -- // runtime format string processing. -- std::string s = fmt::format(FMT_COMPILE("{}"), 42); -- \endrst -- */ --#define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::detail::compiled_string) -- --template <typename T, typename... Tail> --const T& first(const T& value, const Tail&...) { -- return value; --} -- --// Part of a compiled format string. It can be either literal text or a --// replacement field. --template <typename Char> struct format_part { -- enum class kind { arg_index, arg_name, text, replacement }; -+// An output iterator that counts the number of objects written to it and -+// discards them. -+class counting_iterator { -+ private: -+ size_t count_; - -- struct replacement { -- arg_ref<Char> arg_id; -- dynamic_format_specs<Char> specs; -+ public: -+ using iterator_category = std::output_iterator_tag; -+ using difference_type = std::ptrdiff_t; -+ using pointer = void; -+ using reference = void; -+ using _Unchecked_type = counting_iterator; // Mark iterator as checked. -+ -+ struct value_type { -+ template <typename T> void operator=(const T&) {} - }; - -- kind part_kind; -- union value { -- int arg_index; -- basic_string_view<Char> str; -- replacement repl; -- -- FMT_CONSTEXPR value(int index = 0) : arg_index(index) {} -- FMT_CONSTEXPR value(basic_string_view<Char> s) : str(s) {} -- FMT_CONSTEXPR value(replacement r) : repl(r) {} -- } val; -- // Position past the end of the argument id. -- const Char* arg_id_end = nullptr; -+ counting_iterator() : count_(0) {} - -- FMT_CONSTEXPR format_part(kind k = kind::arg_index, value v = {}) -- : part_kind(k), val(v) {} -+ size_t count() const { return count_; } - -- static FMT_CONSTEXPR format_part make_arg_index(int index) { -- return format_part(kind::arg_index, index); -- } -- static FMT_CONSTEXPR format_part make_arg_name(basic_string_view<Char> name) { -- return format_part(kind::arg_name, name); -+ counting_iterator& operator++() { -+ ++count_; -+ return *this; - } -- static FMT_CONSTEXPR format_part make_text(basic_string_view<Char> text) { -- return format_part(kind::text, text); -+ counting_iterator operator++(int) { -+ auto it = *this; -+ ++*this; -+ return it; - } -- static FMT_CONSTEXPR format_part make_replacement(replacement repl) { -- return format_part(kind::replacement, repl); -+ -+ friend counting_iterator operator+(counting_iterator it, difference_type n) { -+ it.count_ += static_cast<size_t>(n); -+ return it; - } -+ -+ value_type operator*() const { return {}; } - }; - --template <typename Char> struct part_counter { -- unsigned num_parts = 0; -+template <typename Char, typename InputIt> -+inline counting_iterator copy_str(InputIt begin, InputIt end, -+ counting_iterator it) { -+ return it + (end - begin); -+} - -- FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { -- if (begin != end) ++num_parts; -- } -+template <typename OutputIt> class truncating_iterator_base { -+ protected: -+ OutputIt out_; -+ size_t limit_; -+ size_t count_ = 0; - -- FMT_CONSTEXPR int on_arg_id() { return ++num_parts, 0; } -- FMT_CONSTEXPR int on_arg_id(int) { return ++num_parts, 0; } -- FMT_CONSTEXPR int on_arg_id(basic_string_view<Char>) { -- return ++num_parts, 0; -- } -+ truncating_iterator_base() : out_(), limit_(0) {} - -- FMT_CONSTEXPR void on_replacement_field(int, const Char*) {} -- -- FMT_CONSTEXPR const Char* on_format_specs(int, const Char* begin, -- const Char* end) { -- // Find the matching brace. -- unsigned brace_counter = 0; -- for (; begin != end; ++begin) { -- if (*begin == '{') { -- ++brace_counter; -- } else if (*begin == '}') { -- if (brace_counter == 0u) break; -- --brace_counter; -- } -- } -- return begin; -- } -+ truncating_iterator_base(OutputIt out, size_t limit) -+ : out_(out), limit_(limit) {} - -- FMT_CONSTEXPR void on_error(const char*) {} -+ public: -+ using iterator_category = std::output_iterator_tag; -+ using value_type = typename std::iterator_traits<OutputIt>::value_type; -+ using difference_type = std::ptrdiff_t; -+ using pointer = void; -+ using reference = void; -+ using _Unchecked_type = -+ truncating_iterator_base; // Mark iterator as checked. -+ -+ OutputIt base() const { return out_; } -+ size_t count() const { return count_; } - }; - --// Counts the number of parts in a format string. --template <typename Char> --FMT_CONSTEXPR unsigned count_parts(basic_string_view<Char> format_str) { -- part_counter<Char> counter; -- parse_format_string<true>(format_str, counter); -- return counter.num_parts; --} -- --template <typename Char, typename PartHandler> --class format_string_compiler : public error_handler { -- private: -- using part = format_part<Char>; -+// An output iterator that truncates the output and counts the number of objects -+// written to it. -+template <typename OutputIt, -+ typename Enable = typename std::is_void< -+ typename std::iterator_traits<OutputIt>::value_type>::type> -+class truncating_iterator; - -- PartHandler handler_; -- part part_; -- basic_string_view<Char> format_str_; -- basic_format_parse_context<Char> parse_context_; -+template <typename OutputIt> -+class truncating_iterator<OutputIt, std::false_type> -+ : public truncating_iterator_base<OutputIt> { -+ mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_; - - public: -- FMT_CONSTEXPR format_string_compiler(basic_string_view<Char> format_str, -- PartHandler handler) -- : handler_(handler), -- format_str_(format_str), -- parse_context_(format_str) {} -- -- FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { -- if (begin != end) -- handler_(part::make_text({begin, to_unsigned(end - begin)})); -- } -- -- FMT_CONSTEXPR int on_arg_id() { -- part_ = part::make_arg_index(parse_context_.next_arg_id()); -- return 0; -- } -+ using value_type = typename truncating_iterator_base<OutputIt>::value_type; - -- FMT_CONSTEXPR int on_arg_id(int id) { -- parse_context_.check_arg_id(id); -- part_ = part::make_arg_index(id); -- return 0; -- } -+ truncating_iterator() = default; - -- FMT_CONSTEXPR int on_arg_id(basic_string_view<Char> id) { -- part_ = part::make_arg_name(id); -- return 0; -- } -+ truncating_iterator(OutputIt out, size_t limit) -+ : truncating_iterator_base<OutputIt>(out, limit) {} - -- FMT_CONSTEXPR void on_replacement_field(int, const Char* ptr) { -- part_.arg_id_end = ptr; -- handler_(part_); -+ truncating_iterator& operator++() { -+ if (this->count_++ < this->limit_) ++this->out_; -+ return *this; - } - -- FMT_CONSTEXPR const Char* on_format_specs(int, const Char* begin, -- const Char* end) { -- auto repl = typename part::replacement(); -- dynamic_specs_handler<basic_format_parse_context<Char>> handler( -- repl.specs, parse_context_); -- auto it = parse_format_specs(begin, end, handler); -- if (*it != '}') on_error("missing '}' in format string"); -- repl.arg_id = part_.part_kind == part::kind::arg_index -- ? arg_ref<Char>(part_.val.arg_index) -- : arg_ref<Char>(part_.val.str); -- auto part = part::make_replacement(repl); -- part.arg_id_end = begin; -- handler_(part); -+ truncating_iterator operator++(int) { -+ auto it = *this; -+ ++*this; - return it; - } --}; -- --// Compiles a format string and invokes handler(part) for each parsed part. --template <bool IS_CONSTEXPR, typename Char, typename PartHandler> --FMT_CONSTEXPR void compile_format_string(basic_string_view<Char> format_str, -- PartHandler handler) { -- parse_format_string<IS_CONSTEXPR>( -- format_str, -- format_string_compiler<Char, PartHandler>(format_str, handler)); --} -- --template <typename OutputIt, typename Context, typename Id> --void format_arg( -- basic_format_parse_context<typename Context::char_type>& parse_ctx, -- Context& ctx, Id arg_id) { -- ctx.advance_to(visit_format_arg( -- arg_formatter<OutputIt, typename Context::char_type>(ctx, &parse_ctx), -- ctx.arg(arg_id))); --} -- --// vformat_to is defined in a subnamespace to prevent ADL. --namespace cf { --template <typename Context, typename OutputIt, typename CompiledFormat> --auto vformat_to(OutputIt out, CompiledFormat& cf, -- basic_format_args<Context> args) -> typename Context::iterator { -- using char_type = typename Context::char_type; -- basic_format_parse_context<char_type> parse_ctx( -- to_string_view(cf.format_str_)); -- Context ctx(out, args); -- -- const auto& parts = cf.parts(); -- for (auto part_it = std::begin(parts); part_it != std::end(parts); -- ++part_it) { -- const auto& part = *part_it; -- const auto& value = part.val; -- -- using format_part_t = format_part<char_type>; -- switch (part.part_kind) { -- case format_part_t::kind::text: { -- const auto text = value.str; -- auto output = ctx.out(); -- auto&& it = reserve(output, text.size()); -- it = std::copy_n(text.begin(), text.size(), it); -- ctx.advance_to(output); -- break; -- } - -- case format_part_t::kind::arg_index: -- advance_to(parse_ctx, part.arg_id_end); -- detail::format_arg<OutputIt>(parse_ctx, ctx, value.arg_index); -- break; -- -- case format_part_t::kind::arg_name: -- advance_to(parse_ctx, part.arg_id_end); -- detail::format_arg<OutputIt>(parse_ctx, ctx, value.str); -- break; -- -- case format_part_t::kind::replacement: { -- const auto& arg_id_value = value.repl.arg_id.val; -- const auto arg = value.repl.arg_id.kind == arg_id_kind::index -- ? ctx.arg(arg_id_value.index) -- : ctx.arg(arg_id_value.name); -- -- auto specs = value.repl.specs; -- -- handle_dynamic_spec<width_checker>(specs.width, specs.width_ref, ctx); -- handle_dynamic_spec<precision_checker>(specs.precision, -- specs.precision_ref, ctx); -- -- error_handler h; -- numeric_specs_checker<error_handler> checker(h, arg.type()); -- if (specs.align == align::numeric) checker.require_numeric_argument(); -- if (specs.sign != sign::none) checker.check_sign(); -- if (specs.alt) checker.require_numeric_argument(); -- if (specs.precision >= 0) checker.check_precision(); -- -- advance_to(parse_ctx, part.arg_id_end); -- ctx.advance_to( -- visit_format_arg(arg_formatter<OutputIt, typename Context::char_type>( -- ctx, nullptr, &specs), -- arg)); -- break; -- } -- } -+ value_type& operator*() const { -+ return this->count_ < this->limit_ ? *this->out_ : blackhole_; - } -- return ctx.out(); --} --} // namespace cf -- --struct basic_compiled_format {}; -+}; - --template <typename S, typename = void> --struct compiled_format_base : basic_compiled_format { -- using char_type = char_t<S>; -- using parts_container = std::vector<detail::format_part<char_type>>; -+template <typename OutputIt> -+class truncating_iterator<OutputIt, std::true_type> -+ : public truncating_iterator_base<OutputIt> { -+ public: -+ truncating_iterator() = default; - -- parts_container compiled_parts; -+ truncating_iterator(OutputIt out, size_t limit) -+ : truncating_iterator_base<OutputIt>(out, limit) {} - -- explicit compiled_format_base(basic_string_view<char_type> format_str) { -- compile_format_string<false>(format_str, -- [this](const format_part<char_type>& part) { -- compiled_parts.push_back(part); -- }); -+ template <typename T> truncating_iterator& operator=(T val) { -+ if (this->count_++ < this->limit_) *this->out_++ = val; -+ return *this; - } - -- const parts_container& parts() const { return compiled_parts; } --}; -- --template <typename Char, unsigned N> struct format_part_array { -- format_part<Char> data[N] = {}; -- FMT_CONSTEXPR format_part_array() = default; -+ truncating_iterator& operator++() { return *this; } -+ truncating_iterator& operator++(int) { return *this; } -+ truncating_iterator& operator*() { return *this; } - }; - --template <typename Char, unsigned N> --FMT_CONSTEXPR format_part_array<Char, N> compile_to_parts( -- basic_string_view<Char> format_str) { -- format_part_array<Char, N> parts; -- unsigned counter = 0; -- // This is not a lambda for compatibility with older compilers. -- struct { -- format_part<Char>* parts; -- unsigned* counter; -- FMT_CONSTEXPR void operator()(const format_part<Char>& part) { -- parts[(*counter)++] = part; -- } -- } collector{parts.data, &counter}; -- compile_format_string<true>(format_str, collector); -- if (counter < N) { -- parts.data[counter] = -- format_part<Char>::make_text(basic_string_view<Char>()); -- } -- return parts; --} -- --template <typename T> constexpr const T& constexpr_max(const T& a, const T& b) { -- return (a < b) ? b : a; --} -+// A compile-time string which is compiled into fast formatting code. -+class compiled_string {}; - - template <typename S> --struct compiled_format_base<S, enable_if_t<is_compile_string<S>::value>> -- : basic_compiled_format { -- using char_type = char_t<S>; -+struct is_compiled_string : std::is_base_of<compiled_string, S> {}; -+ -+/** -+ \rst -+ Converts a string literal *s* into a format string that will be parsed at -+ compile time and converted into efficient formatting code. Requires C++17 -+ ``constexpr if`` compiler support. - -- FMT_CONSTEXPR explicit compiled_format_base(basic_string_view<char_type>) {} -+ **Example**:: - --// Workaround for old compilers. Format string compilation will not be --// performed there anyway. --#if FMT_USE_CONSTEXPR -- static FMT_CONSTEXPR_DECL const unsigned num_format_parts = -- constexpr_max(count_parts(to_string_view(S())), 1u); -+ // Converts 42 into std::string using the most efficient method and no -+ // runtime format string processing. -+ std::string s = fmt::format(FMT_COMPILE("{}"), 42); -+ \endrst -+ */ -+#ifdef __cpp_if_constexpr -+# define FMT_COMPILE(s) \ -+ FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) - #else -- static const unsigned num_format_parts = 1; -+# define FMT_COMPILE(s) FMT_STRING(s) - #endif - -- using parts_container = format_part<char_type>[num_format_parts]; -- -- const parts_container& parts() const { -- static FMT_CONSTEXPR_DECL const auto compiled_parts = -- compile_to_parts<char_type, num_format_parts>( -- detail::to_string_view(S())); -- return compiled_parts.data; -+#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -+template <typename Char, size_t N, -+ fmt::detail_exported::fixed_string<Char, N> Str> -+struct udl_compiled_string : compiled_string { -+ using char_type = Char; -+ constexpr operator basic_string_view<char_type>() const { -+ return {Str.data, N - 1}; - } - }; -+#endif - --template <typename S, typename... Args> --class compiled_format : private compiled_format_base<S> { -- public: -- using typename compiled_format_base<S>::char_type; -- -- private: -- basic_string_view<char_type> format_str_; -- -- template <typename Context, typename OutputIt, typename CompiledFormat> -- friend auto cf::vformat_to(OutputIt out, CompiledFormat& cf, -- basic_format_args<Context> args) -> -- typename Context::iterator; -- -- public: -- compiled_format() = delete; -- explicit constexpr compiled_format(basic_string_view<char_type> format_str) -- : compiled_format_base<S>(format_str), format_str_(format_str) {} --}; -+template <typename T, typename... Tail> -+const T& first(const T& value, const Tail&...) { -+ return value; -+} - - #ifdef __cpp_if_constexpr - template <typename... Args> struct type_list {}; -@@ -377,6 +193,12 @@ constexpr const auto& get([[maybe_unused]] const T& first, - return get<N - 1>(rest...); - } - -+template <typename Char, typename... Args> -+constexpr int get_arg_index_by_name(basic_string_view<Char> name, -+ type_list<Args...>) { -+ return get_arg_index_by_name<Args...>(name); -+} -+ - template <int N, typename> struct get_type_impl; - - template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> { -@@ -393,7 +215,7 @@ template <typename Char> struct text { - using char_type = Char; - - template <typename OutputIt, typename... Args> -- OutputIt format(OutputIt out, const Args&...) const { -+ constexpr OutputIt format(OutputIt out, const Args&...) const { - return write<Char>(out, data); - } - }; -@@ -412,11 +234,22 @@ template <typename Char> struct code_unit { - using char_type = Char; - - template <typename OutputIt, typename... Args> -- OutputIt format(OutputIt out, const Args&...) const { -+ constexpr OutputIt format(OutputIt out, const Args&...) const { - return write<Char>(out, value); - } - }; - -+// This ensures that the argument type is convertible to `const T&`. -+template <typename T, int N, typename... Args> -+constexpr const T& get_arg_checked(const Args&... args) { -+ const auto& arg = get<N>(args...); -+ if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) { -+ return arg.value; -+ } else { -+ return arg; -+ } -+} -+ - template <typename Char> - struct is_compiled_format<code_unit<Char>> : std::true_type {}; - -@@ -425,29 +258,58 @@ template <typename Char, typename T, int N> struct field { - using char_type = Char; - - template <typename OutputIt, typename... Args> -- OutputIt format(OutputIt out, const Args&... args) const { -- // This ensures that the argument type is convertile to `const T&`. -- const T& arg = get<N>(args...); -- return write<Char>(out, arg); -+ constexpr OutputIt format(OutputIt out, const Args&... args) const { -+ return write<Char>(out, get_arg_checked<T, N>(args...)); - } - }; - - template <typename Char, typename T, int N> - struct is_compiled_format<field<Char, T, N>> : std::true_type {}; - -+// A replacement field that refers to argument with name. -+template <typename Char> struct runtime_named_field { -+ using char_type = Char; -+ basic_string_view<Char> name; -+ -+ template <typename OutputIt, typename T> -+ constexpr static bool try_format_argument( -+ OutputIt& out, -+ // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9 -+ [[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) { -+ if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) { -+ if (arg_name == arg.name) { -+ out = write<Char>(out, arg.value); -+ return true; -+ } -+ } -+ return false; -+ } -+ -+ template <typename OutputIt, typename... Args> -+ constexpr OutputIt format(OutputIt out, const Args&... args) const { -+ bool found = (try_format_argument(out, name, args) || ...); -+ if (!found) { -+ throw format_error("argument with specified name is not found"); -+ } -+ return out; -+ } -+}; -+ -+template <typename Char> -+struct is_compiled_format<runtime_named_field<Char>> : std::true_type {}; -+ - // A replacement field that refers to argument N and has format specifiers. - template <typename Char, typename T, int N> struct spec_field { - using char_type = Char; -- mutable formatter<T, Char> fmt; -+ formatter<T, Char> fmt; - - template <typename OutputIt, typename... Args> -- OutputIt format(OutputIt out, const Args&... args) const { -- // This ensures that the argument type is convertile to `const T&`. -- const T& arg = get<N>(args...); -+ constexpr FMT_INLINE OutputIt format(OutputIt out, -+ const Args&... args) const { - const auto& vargs = -- make_format_args<basic_format_context<OutputIt, Char>>(args...); -+ fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...); - basic_format_context<OutputIt, Char> ctx(out, vargs); -- return fmt.format(arg, ctx); -+ return fmt.format(get_arg_checked<T, N>(args...), ctx); - } - }; - -@@ -460,7 +322,7 @@ template <typename L, typename R> struct concat { - using char_type = typename L::char_type; - - template <typename OutputIt, typename... Args> -- OutputIt format(OutputIt out, const Args&... args) const { -+ constexpr OutputIt format(OutputIt out, const Args&... args) const { - out = lhs.format(out, args...); - return rhs.format(out, args...); - } -@@ -508,14 +370,77 @@ template <typename T, typename Char> struct parse_specs_result { - int next_arg_id; - }; - -+constexpr int manual_indexing_id = -1; -+ - template <typename T, typename Char> - constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str, -- size_t pos, int arg_id) { -+ size_t pos, int next_arg_id) { - str.remove_prefix(pos); -- auto ctx = basic_format_parse_context<Char>(str, {}, arg_id + 1); -+ auto ctx = basic_format_parse_context<Char>(str, {}, next_arg_id); - auto f = formatter<T, Char>(); - auto end = f.parse(ctx); -- return {f, pos + (end - str.data()) + 1, ctx.next_arg_id()}; -+ return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1, -+ next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; -+} -+ -+template <typename Char> struct arg_id_handler { -+ arg_ref<Char> arg_id; -+ -+ constexpr int operator()() { -+ FMT_ASSERT(false, "handler cannot be used with automatic indexing"); -+ return 0; -+ } -+ constexpr int operator()(int id) { -+ arg_id = arg_ref<Char>(id); -+ return 0; -+ } -+ constexpr int operator()(basic_string_view<Char> id) { -+ arg_id = arg_ref<Char>(id); -+ return 0; -+ } -+ -+ constexpr void on_error(const char* message) { throw format_error(message); } -+}; -+ -+template <typename Char> struct parse_arg_id_result { -+ arg_ref<Char> arg_id; -+ const Char* arg_id_end; -+}; -+ -+template <int ID, typename Char> -+constexpr auto parse_arg_id(const Char* begin, const Char* end) { -+ auto handler = arg_id_handler<Char>{arg_ref<Char>{}}; -+ auto arg_id_end = parse_arg_id(begin, end, handler); -+ return parse_arg_id_result<Char>{handler.arg_id, arg_id_end}; -+} -+ -+template <typename T, typename Enable = void> struct field_type { -+ using type = remove_cvref_t<T>; -+}; -+ -+template <typename T> -+struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> { -+ using type = remove_cvref_t<decltype(T::value)>; -+}; -+ -+template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID, -+ typename S> -+constexpr auto parse_replacement_field_then_tail(S format_str) { -+ using char_type = typename S::char_type; -+ constexpr auto str = basic_string_view<char_type>(format_str); -+ constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); -+ if constexpr (c == '}') { -+ return parse_tail<Args, END_POS + 1, NEXT_ID>( -+ field<char_type, typename field_type<T>::type, ARG_INDEX>(), -+ format_str); -+ } else if constexpr (c == ':') { -+ constexpr auto result = parse_specs<typename field_type<T>::type>( -+ str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); -+ return parse_tail<Args, result.end, result.next_arg_id>( -+ spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{ -+ result.fmt}, -+ format_str); -+ } - } - - // Compiles a non-empty format string and returns the compiled representation -@@ -523,26 +448,58 @@ constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str, - template <typename Args, size_t POS, int ID, typename S> - constexpr auto compile_format_string(S format_str) { - using char_type = typename S::char_type; -- constexpr basic_string_view<char_type> str = format_str; -+ constexpr auto str = basic_string_view<char_type>(format_str); - if constexpr (str[POS] == '{') { -- if (POS + 1 == str.size()) -+ if constexpr (POS + 1 == str.size()) - throw format_error("unmatched '{' in format string"); - if constexpr (str[POS + 1] == '{') { - return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str); -- } else if constexpr (str[POS + 1] == '}') { -- using type = get_type<ID, Args>; -- return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(), -- format_str); -- } else if constexpr (str[POS + 1] == ':') { -- using type = get_type<ID, Args>; -- constexpr auto result = parse_specs<type>(str, POS + 2, ID); -- return parse_tail<Args, result.end, result.next_arg_id>( -- spec_field<char_type, type, ID>{result.fmt}, format_str); -+ } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { -+ static_assert(ID != manual_indexing_id, -+ "cannot switch from manual to automatic argument indexing"); -+ constexpr auto next_id = -+ ID != manual_indexing_id ? ID + 1 : manual_indexing_id; -+ return parse_replacement_field_then_tail<get_type<ID, Args>, Args, -+ POS + 1, ID, next_id>( -+ format_str); - } else { -- return unknown_format(); -+ constexpr auto arg_id_result = -+ parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size()); -+ constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data(); -+ constexpr char_type c = -+ arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); -+ static_assert(c == '}' || c == ':', "missing '}' in format string"); -+ if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { -+ static_assert( -+ ID == manual_indexing_id || ID == 0, -+ "cannot switch from automatic to manual argument indexing"); -+ constexpr auto arg_index = arg_id_result.arg_id.val.index; -+ return parse_replacement_field_then_tail<get_type<arg_index, Args>, -+ Args, arg_id_end_pos, -+ arg_index, manual_indexing_id>( -+ format_str); -+ } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { -+ constexpr auto arg_index = -+ get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); -+ if constexpr (arg_index != invalid_arg_index) { -+ constexpr auto next_id = -+ ID != manual_indexing_id ? ID + 1 : manual_indexing_id; -+ return parse_replacement_field_then_tail< -+ decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos, -+ arg_index, next_id>(format_str); -+ } else { -+ if constexpr (c == '}') { -+ return parse_tail<Args, arg_id_end_pos + 1, ID>( -+ runtime_named_field<char_type>{arg_id_result.arg_id.val.name}, -+ format_str); -+ } else if constexpr (c == ':') { -+ return unknown_format(); // no type info for specs parsing -+ } -+ } -+ } - } - } else if constexpr (str[POS] == '}') { -- if (POS + 1 == str.size()) -+ if constexpr (POS + 1 == str.size()) - throw format_error("unmatched '}' in format string"); - return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str); - } else { -@@ -558,144 +515,125 @@ constexpr auto compile_format_string(S format_str) { - } - - template <typename... Args, typename S, -- FMT_ENABLE_IF(is_compile_string<S>::value || -- detail::is_compiled_string<S>::value)> -+ FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> - constexpr auto compile(S format_str) { -- constexpr basic_string_view<typename S::char_type> str = format_str; -+ constexpr auto str = basic_string_view<typename S::char_type>(format_str); - if constexpr (str.size() == 0) { - return detail::make_text(str, 0, 0); - } else { - constexpr auto result = - detail::compile_format_string<detail::type_list<Args...>, 0, 0>( - format_str); -- if constexpr (std::is_same<remove_cvref_t<decltype(result)>, -- detail::unknown_format>()) { -- return detail::compiled_format<S, Args...>(to_string_view(format_str)); -- } else { -- return result; -- } -+ return result; - } - } --#else --template <typename... Args, typename S, -- FMT_ENABLE_IF(is_compile_string<S>::value)> --constexpr auto compile(S format_str) -> detail::compiled_format<S, Args...> { -- return detail::compiled_format<S, Args...>(to_string_view(format_str)); --} - #endif // __cpp_if_constexpr -- --// Compiles the format string which must be a string literal. --template <typename... Args, typename Char, size_t N> --auto compile(const Char (&format_str)[N]) -- -> detail::compiled_format<const Char*, Args...> { -- return detail::compiled_format<const Char*, Args...>( -- basic_string_view<Char>(format_str, N - 1)); --} - } // namespace detail - --// DEPRECATED! use FMT_COMPILE instead. --template <typename... Args> --FMT_DEPRECATED auto compile(const Args&... args) -- -> decltype(detail::compile(args...)) { -- return detail::compile(args...); --} -+FMT_MODULE_EXPORT_BEGIN - --#if FMT_USE_CONSTEXPR --# ifdef __cpp_if_constexpr -+#ifdef __cpp_if_constexpr - - template <typename CompiledFormat, typename... Args, - typename Char = typename CompiledFormat::char_type, - FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)> - FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf, - const Args&... args) { -- basic_memory_buffer<Char> buffer; -- cf.format(detail::buffer_appender<Char>(buffer), args...); -- return to_string(buffer); -+ auto s = std::basic_string<Char>(); -+ cf.format(std::back_inserter(s), args...); -+ return s; - } - - template <typename OutputIt, typename CompiledFormat, typename... Args, - FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)> --OutputIt format_to(OutputIt out, const CompiledFormat& cf, -- const Args&... args) { -+constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf, -+ const Args&... args) { - return cf.format(out, args...); - } --# endif // __cpp_if_constexpr --#endif // FMT_USE_CONSTEXPR -- --template <typename CompiledFormat, typename... Args, -- typename Char = typename CompiledFormat::char_type, -- FMT_ENABLE_IF(std::is_base_of<detail::basic_compiled_format, -- CompiledFormat>::value)> --std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) { -- basic_memory_buffer<Char> buffer; -- using context = buffer_context<Char>; -- detail::cf::vformat_to<context>(detail::buffer_appender<Char>(buffer), cf, -- make_format_args<context>(args...)); -- return to_string(buffer); --} - - template <typename S, typename... Args, - FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> - FMT_INLINE std::basic_string<typename S::char_type> format(const S&, - Args&&... args) { --#ifdef __cpp_if_constexpr - if constexpr (std::is_same<typename S::char_type, char>::value) { -- constexpr basic_string_view<typename S::char_type> str = S(); -- if (str.size() == 2 && str[0] == '{' && str[1] == '}') -- return fmt::to_string(detail::first(args...)); -+ constexpr auto str = basic_string_view<typename S::char_type>(S()); -+ if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { -+ const auto& first = detail::first(args...); -+ if constexpr (detail::is_named_arg< -+ remove_cvref_t<decltype(first)>>::value) { -+ return fmt::to_string(first.value); -+ } else { -+ return fmt::to_string(first); -+ } -+ } - } --#endif - constexpr auto compiled = detail::compile<Args...>(S()); -- return format(compiled, std::forward<Args>(args)...); --} -- --template <typename OutputIt, typename CompiledFormat, typename... Args, -- FMT_ENABLE_IF(std::is_base_of<detail::basic_compiled_format, -- CompiledFormat>::value)> --OutputIt format_to(OutputIt out, const CompiledFormat& cf, -- const Args&... args) { -- using char_type = typename CompiledFormat::char_type; -- using context = format_context_t<OutputIt, char_type>; -- return detail::cf::vformat_to<context>(out, cf, -- make_format_args<context>(args...)); -+ if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>, -+ detail::unknown_format>()) { -+ return format(static_cast<basic_string_view<typename S::char_type>>(S()), -+ std::forward<Args>(args)...); -+ } else { -+ return format(compiled, std::forward<Args>(args)...); -+ } - } - - template <typename OutputIt, typename S, typename... Args, - FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> --OutputIt format_to(OutputIt out, const S&, const Args&... args) { -+FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { - constexpr auto compiled = detail::compile<Args...>(S()); -- return format_to(out, compiled, args...); -+ if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>, -+ detail::unknown_format>()) { -+ return format_to(out, -+ static_cast<basic_string_view<typename S::char_type>>(S()), -+ std::forward<Args>(args)...); -+ } else { -+ return format_to(out, compiled, std::forward<Args>(args)...); -+ } - } -+#endif - --template <typename OutputIt, typename CompiledFormat, typename... Args> --auto format_to_n(OutputIt out, size_t n, const CompiledFormat& cf, -- const Args&... args) -> -- typename std::enable_if< -- detail::is_output_iterator<OutputIt, -- typename CompiledFormat::char_type>::value && -- std::is_base_of<detail::basic_compiled_format, -- CompiledFormat>::value, -- format_to_n_result<OutputIt>>::type { -- auto it = -- format_to(detail::truncating_iterator<OutputIt>(out, n), cf, args...); -+template <typename OutputIt, typename S, typename... Args, -+ FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> -+format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, -+ const S& format_str, Args&&... args) { -+ auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), format_str, -+ std::forward<Args>(args)...); - return {it.base(), it.count()}; - } - --template <typename OutputIt, typename S, typename... Args, -+template <typename S, typename... Args, - FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> --format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, const S&, -- const Args&... args) { -- constexpr auto compiled = detail::compile<Args...>(S()); -- auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), compiled, -- args...); -- return {it.base(), it.count()}; -+size_t formatted_size(const S& format_str, const Args&... args) { -+ return format_to(detail::counting_iterator(), format_str, args...).count(); - } - --template <typename CompiledFormat, typename... Args> --size_t formatted_size(const CompiledFormat& cf, const Args&... args) { -- return format_to(detail::counting_iterator(), cf, args...).count(); -+template <typename S, typename... Args, -+ FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> -+void print(std::FILE* f, const S& format_str, const Args&... args) { -+ memory_buffer buffer; -+ format_to(std::back_inserter(buffer), format_str, args...); -+ detail::print(f, {buffer.data(), buffer.size()}); - } - -+template <typename S, typename... Args, -+ FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> -+void print(const S& format_str, const Args&... args) { -+ print(stdout, format_str, args...); -+} -+ -+#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -+inline namespace literals { -+template <detail_exported::fixed_string Str> -+constexpr detail::udl_compiled_string< -+ remove_cvref_t<decltype(Str.data[0])>, -+ sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str> -+operator""_cf() { -+ return {}; -+} -+} // namespace literals -+#endif -+ -+FMT_MODULE_EXPORT_END - FMT_END_NAMESPACE - - #endif // FMT_COMPILE_H_ -diff --git a/include/spdlog/fmt/bundled/core.h b/include/spdlog/fmt/bundled/core.h -index 0a81e0cc..14e8c914 100644 ---- a/include/spdlog/fmt/bundled/core.h -+++ b/include/spdlog/fmt/bundled/core.h -@@ -1,4 +1,4 @@ --// Formatting library for C++ - the core API -+// Formatting library for C++ - the core API for char/UTF-8 - // - // Copyright (c) 2012 - present, Victor Zverovich - // All rights reserved. -@@ -10,15 +10,13 @@ - - #include <cstdio> // std::FILE - #include <cstring> --#include <functional> - #include <iterator> --#include <memory> -+#include <limits> - #include <string> - #include <type_traits> --#include <vector> - - // The fmt library version in the form major * 10000 + minor * 100 + patch. --#define FMT_VERSION 70103 -+#define FMT_VERSION 80000 - - #ifdef __clang__ - # define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) -@@ -28,14 +26,10 @@ - - #if defined(__GNUC__) && !defined(__clang__) - # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -+# define FMT_GCC_PRAGMA(arg) _Pragma(arg) - #else - # define FMT_GCC_VERSION 0 --#endif -- --#if defined(__INTEL_COMPILER) --# define FMT_ICC_VERSION __INTEL_COMPILER --#else --# define FMT_ICC_VERSION 0 -+# define FMT_GCC_PRAGMA(arg) - #endif - - #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) -@@ -44,6 +38,12 @@ - # define FMT_HAS_GXX_CXX11 0 - #endif - -+#if defined(__INTEL_COMPILER) -+# define FMT_ICC_VERSION __INTEL_COMPILER -+#else -+# define FMT_ICC_VERSION 0 -+#endif -+ - #ifdef __NVCC__ - # define FMT_NVCC __NVCC__ - #else -@@ -52,10 +52,10 @@ - - #ifdef _MSC_VER - # define FMT_MSC_VER _MSC_VER --# define FMT_SUPPRESS_MSC_WARNING(n) __pragma(warning(suppress : n)) -+# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) - #else - # define FMT_MSC_VER 0 --# define FMT_SUPPRESS_MSC_WARNING(n) -+# define FMT_MSC_WARNING(...) - #endif - - #ifdef __has_feature -@@ -95,10 +95,26 @@ - # define FMT_CONSTEXPR constexpr - # define FMT_CONSTEXPR_DECL constexpr - #else --# define FMT_CONSTEXPR inline -+# define FMT_CONSTEXPR - # define FMT_CONSTEXPR_DECL - #endif - -+// Check if constexpr std::char_traits<>::compare,length is supported. -+#if defined(__GLIBCXX__) -+# if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \ -+ _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE. -+# define FMT_CONSTEXPR_CHAR_TRAITS constexpr -+# endif -+#elif defined(_LIBCPP_VERSION) && __cplusplus >= 201703L && \ -+ _LIBCPP_VERSION >= 4000 -+# define FMT_CONSTEXPR_CHAR_TRAITS constexpr -+#elif FMT_MSC_VER >= 1914 && _MSVC_LANG >= 201703L -+# define FMT_CONSTEXPR_CHAR_TRAITS constexpr -+#endif -+#ifndef FMT_CONSTEXPR_CHAR_TRAITS -+# define FMT_CONSTEXPR_CHAR_TRAITS -+#endif -+ - #ifndef FMT_OVERRIDE - # if FMT_HAS_FEATURE(cxx_override_control) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 -@@ -149,25 +165,40 @@ - # define FMT_NORETURN - #endif - --#ifndef FMT_DEPRECATED --# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900 --# define FMT_DEPRECATED [[deprecated]] -+#ifndef FMT_MAYBE_UNUSED -+# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) -+# define FMT_MAYBE_UNUSED [[maybe_unused]] - # else --# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__) --# define FMT_DEPRECATED __attribute__((deprecated)) --# elif FMT_MSC_VER --# define FMT_DEPRECATED __declspec(deprecated) --# else --# define FMT_DEPRECATED /* deprecated */ --# endif -+# define FMT_MAYBE_UNUSED - # endif - #endif - --// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers. --#if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC --# define FMT_DEPRECATED_ALIAS -+#if __cplusplus == 201103L || __cplusplus == 201402L -+# if defined(__INTEL_COMPILER) || defined(__PGI) -+# define FMT_FALLTHROUGH -+# elif defined(__clang__) -+# define FMT_FALLTHROUGH [[clang::fallthrough]] -+# elif FMT_GCC_VERSION >= 700 && \ -+ (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) -+# define FMT_FALLTHROUGH [[gnu::fallthrough]] -+# else -+# define FMT_FALLTHROUGH -+# endif -+#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) || \ -+ (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -+# define FMT_FALLTHROUGH [[fallthrough]] - #else --# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED -+# define FMT_FALLTHROUGH -+#endif -+ -+#ifndef FMT_USE_FLOAT -+# define FMT_USE_FLOAT 1 -+#endif -+#ifndef FMT_USE_DOUBLE -+# define FMT_USE_DOUBLE 1 -+#endif -+#ifndef FMT_USE_LONG_DOUBLE -+# define FMT_USE_LONG_DOUBLE 1 - #endif - - #ifndef FMT_INLINE -@@ -180,7 +211,7 @@ - - #ifndef FMT_USE_INLINE_NAMESPACES - # if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \ -- (FMT_MSC_VER >= 1900 && !_MANAGED) -+ (FMT_MSC_VER >= 1900 && (!defined(_MANAGED) || !_MANAGED)) - # define FMT_USE_INLINE_NAMESPACES 1 - # else - # define FMT_USE_INLINE_NAMESPACES 0 -@@ -197,41 +228,45 @@ - # define FMT_INLINE_NAMESPACE namespace - # define FMT_END_NAMESPACE \ - } \ -- using namespace v7; \ -+ using namespace v8; \ - } - # endif - # define FMT_BEGIN_NAMESPACE \ - namespace fmt { \ -- FMT_INLINE_NAMESPACE v7 { -+ FMT_INLINE_NAMESPACE v8 { -+#endif -+ -+#ifndef FMT_MODULE_EXPORT -+# define FMT_MODULE_EXPORT -+# define FMT_MODULE_EXPORT_BEGIN -+# define FMT_MODULE_EXPORT_END -+# define FMT_BEGIN_DETAIL_NAMESPACE namespace detail { -+# define FMT_END_DETAIL_NAMESPACE } - #endif - - #if !defined(FMT_HEADER_ONLY) && defined(_WIN32) --# define FMT_CLASS_API FMT_SUPPRESS_MSC_WARNING(4275) -+# define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275) - # ifdef FMT_EXPORT - # define FMT_API __declspec(dllexport) --# define FMT_EXTERN_TEMPLATE_API FMT_API --# define FMT_EXPORTED - # elif defined(FMT_SHARED) - # define FMT_API __declspec(dllimport) --# define FMT_EXTERN_TEMPLATE_API FMT_API - # endif - #else - # define FMT_CLASS_API -+# if defined(FMT_EXPORT) || defined(FMT_SHARED) -+# if defined(__GNUC__) || defined(__clang__) -+# define FMT_API __attribute__((visibility("default"))) -+# endif -+# endif - #endif - #ifndef FMT_API - # define FMT_API - #endif --#ifndef FMT_EXTERN_TEMPLATE_API --# define FMT_EXTERN_TEMPLATE_API --#endif --#ifndef FMT_INSTANTIATION_DEF_API --# define FMT_INSTANTIATION_DEF_API FMT_API --#endif - --#ifndef FMT_HEADER_ONLY --# define FMT_EXTERN extern -+#if FMT_GCC_VERSION -+# define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) - #else --# define FMT_EXTERN -+# define FMT_GCC_VISIBILITY_HIDDEN - #endif - - // libc++ supports string_view in pre-c++17. -@@ -248,11 +283,37 @@ - #ifndef FMT_UNICODE - # define FMT_UNICODE !FMT_MSC_VER - #endif --#if FMT_UNICODE && FMT_MSC_VER --# pragma execution_character_set("utf-8") -+ -+#ifndef FMT_CONSTEVAL -+# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \ -+ __cplusplus > 201703L) || \ -+ (defined(__cpp_consteval) && \ -+ !FMT_MSC_VER) // consteval is broken in MSVC. -+# define FMT_CONSTEVAL consteval -+# define FMT_HAS_CONSTEVAL -+# else -+# define FMT_CONSTEVAL -+# endif -+#endif -+ -+#ifndef FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -+# if defined(__cpp_nontype_template_args) && \ -+ ((FMT_GCC_VERSION >= 903 && __cplusplus >= 201709L) || \ -+ __cpp_nontype_template_args >= 201911L) -+# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 1 -+# else -+# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 0 -+# endif -+#endif -+ -+// Enable minimal optimizations for more compact code in debug mode. -+FMT_GCC_PRAGMA("GCC push_options") -+#ifndef __OPTIMIZE__ -+FMT_GCC_PRAGMA("GCC optimize(\"Og\")") - #endif - - FMT_BEGIN_NAMESPACE -+FMT_MODULE_EXPORT_BEGIN - - // Implementations of enable_if_t and other metafunctions for older systems. - template <bool B, class T = void> -@@ -263,23 +324,35 @@ template <bool B> using bool_constant = std::integral_constant<bool, B>; - template <typename T> - using remove_reference_t = typename std::remove_reference<T>::type; - template <typename T> --using remove_const_t = typename std::remove_const<T>::type; --template <typename T> - using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type; - template <typename T> struct type_identity { using type = T; }; - template <typename T> using type_identity_t = typename type_identity<T>::type; - --struct monostate {}; -+struct monostate { -+ constexpr monostate() {} -+}; - - // 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 -+#ifdef FMT_DOC -+# define FMT_ENABLE_IF(...) -+#else -+# define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0 -+#endif - --namespace detail { -+FMT_BEGIN_DETAIL_NAMESPACE -+ -+constexpr FMT_INLINE auto is_constant_evaluated() FMT_NOEXCEPT -> bool { -+#ifdef __cpp_lib_is_constant_evaluated -+ return std::is_constant_evaluated(); -+#else -+ return false; -+#endif -+} - --// A helper function to suppress "conditional expression is constant" warnings. --template <typename T> constexpr T const_check(T value) { return value; } -+// A function to suppress "conditional expression is constant" warnings. -+template <typename T> constexpr auto const_check(T value) -> T { return value; } - - FMT_NORETURN FMT_API void assert_fail(const char* file, int line, - const char* message); -@@ -312,38 +385,39 @@ template <typename T> struct std_string_view {}; - # define FMT_USE_INT128 1 - using int128_t = __int128_t; - using uint128_t = __uint128_t; -+template <typename T> inline auto convert_for_visit(T value) -> T { -+ return value; -+} - #else - # define FMT_USE_INT128 0 - #endif - #if !FMT_USE_INT128 --struct int128_t {}; --struct uint128_t {}; -+enum class int128_t {}; -+enum class uint128_t {}; -+// Reduce template instantiations. -+template <typename T> inline auto convert_for_visit(T) -> monostate { -+ return {}; -+} - #endif - - // Casts a nonnegative integer to unsigned. - template <typename Int> --FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) { -+FMT_CONSTEXPR auto to_unsigned(Int value) -> -+ typename std::make_unsigned<Int>::type { - FMT_ASSERT(value >= 0, "negative value"); - return static_cast<typename std::make_unsigned<Int>::type>(value); - } - --FMT_SUPPRESS_MSC_WARNING(4566) constexpr unsigned char micro[] = "\u00B5"; -+FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5"; - --template <typename Char> constexpr bool is_unicode() { -- return FMT_UNICODE || sizeof(Char) != 1 || -- (sizeof(micro) == 3 && micro[0] == 0xC2 && micro[1] == 0xB5); -+constexpr auto is_utf8() -> bool { -+ // Avoid buggy sign extensions in MSVC's constant evaluation mode. -+ // https://developercommunity.visualstudio.com/t/C-difference-in-behavior-for-unsigned/1233612 -+ using uchar = unsigned char; -+ return FMT_UNICODE || (sizeof(micro) == 3 && uchar(micro[0]) == 0xC2 && -+ uchar(micro[1]) == 0xB5); - } -- --#ifdef __cpp_char8_t --using char8_type = char8_t; --#else --enum char8_type : unsigned char {}; --#endif --} // namespace detail -- --#ifdef FMT_USE_INTERNAL --namespace internal = detail; // DEPRECATED --#endif -+FMT_END_DETAIL_NAMESPACE - - /** - An implementation of ``std::basic_string_view`` for pre-C++17. It provides a -@@ -374,11 +448,15 @@ template <typename Char> class basic_string_view { - the size with ``std::char_traits<Char>::length``. - \endrst - */ --#if __cplusplus >= 201703L // C++17's char_traits::length() is constexpr. -- FMT_CONSTEXPR --#endif -- basic_string_view(const Char* s) -- : data_(s), size_(std::char_traits<Char>::length(s)) {} -+ FMT_CONSTEXPR_CHAR_TRAITS -+ FMT_INLINE -+ basic_string_view(const Char* s) : data_(s) { -+ if (detail::const_check(std::is_same<Char, char>::value && -+ !detail::is_constant_evaluated())) -+ size_ = std::strlen(reinterpret_cast<const char*>(s)); -+ else -+ size_ = std::char_traits<Char>::length(s); -+ } - - /** Constructs a string reference from a ``std::basic_string`` object. */ - template <typename Traits, typename Alloc> -@@ -393,15 +471,17 @@ template <typename Char> class basic_string_view { - size_(s.size()) {} - - /** Returns a pointer to the string data. */ -- constexpr const Char* data() const { return data_; } -+ constexpr auto data() const -> const Char* { return data_; } - - /** Returns the string size. */ -- constexpr size_t size() const { return size_; } -+ constexpr auto size() const -> size_t { return size_; } - -- constexpr iterator begin() const { return data_; } -- constexpr iterator end() const { return data_ + size_; } -+ constexpr auto begin() const -> iterator { return data_; } -+ constexpr auto end() const -> iterator { return data_ + size_; } - -- constexpr const Char& operator[](size_t pos) const { return data_[pos]; } -+ constexpr auto operator[](size_t pos) const -> const Char& { -+ return data_[pos]; -+ } - - FMT_CONSTEXPR void remove_prefix(size_t n) { - data_ += n; -@@ -409,7 +489,7 @@ template <typename Char> class basic_string_view { - } - - // Lexicographically compare this string reference to other. -- int compare(basic_string_view other) const { -+ FMT_CONSTEXPR_CHAR_TRAITS auto compare(basic_string_view other) const -> int { - size_t str_size = size_ < other.size_ ? size_ : other.size_; - int result = std::char_traits<Char>::compare(data_, other.data_, str_size); - if (result == 0) -@@ -417,36 +497,33 @@ template <typename Char> class basic_string_view { - return result; - } - -- friend bool operator==(basic_string_view lhs, basic_string_view rhs) { -+ FMT_CONSTEXPR_CHAR_TRAITS friend auto operator==(basic_string_view lhs, -+ basic_string_view rhs) -+ -> bool { - return lhs.compare(rhs) == 0; - } -- friend bool operator!=(basic_string_view lhs, basic_string_view rhs) { -+ friend auto operator!=(basic_string_view lhs, basic_string_view rhs) -> bool { - return lhs.compare(rhs) != 0; - } -- friend bool operator<(basic_string_view lhs, basic_string_view rhs) { -+ friend auto operator<(basic_string_view lhs, basic_string_view rhs) -> bool { - return lhs.compare(rhs) < 0; - } -- friend bool operator<=(basic_string_view lhs, basic_string_view rhs) { -+ friend auto operator<=(basic_string_view lhs, basic_string_view rhs) -> bool { - return lhs.compare(rhs) <= 0; - } -- friend bool operator>(basic_string_view lhs, basic_string_view rhs) { -+ friend auto operator>(basic_string_view lhs, basic_string_view rhs) -> bool { - return lhs.compare(rhs) > 0; - } -- friend bool operator>=(basic_string_view lhs, basic_string_view rhs) { -+ friend auto operator>=(basic_string_view lhs, basic_string_view rhs) -> bool { - return lhs.compare(rhs) >= 0; - } - }; - - using string_view = basic_string_view<char>; --using wstring_view = basic_string_view<wchar_t>; - - /** 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<detail::char8_type> : std::true_type {}; --template <> struct is_char<char16_t> : std::true_type {}; --template <> struct is_char<char32_t> : std::true_type {}; - - /** - \rst -@@ -465,24 +542,26 @@ template <> struct is_char<char32_t> : std::true_type {}; - \endrst - */ - template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)> --inline basic_string_view<Char> to_string_view(const Char* s) { -+FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view<Char> { - return s; - } - - template <typename Char, typename Traits, typename Alloc> --inline basic_string_view<Char> to_string_view( -- const std::basic_string<Char, Traits, Alloc>& s) { -+inline auto to_string_view(const std::basic_string<Char, Traits, Alloc>& s) -+ -> basic_string_view<Char> { - return s; - } - - template <typename Char> --inline basic_string_view<Char> to_string_view(basic_string_view<Char> s) { -+constexpr auto to_string_view(basic_string_view<Char> s) -+ -> basic_string_view<Char> { - return s; - } - - template <typename Char, - FMT_ENABLE_IF(!std::is_empty<detail::std_string_view<Char>>::value)> --inline basic_string_view<Char> to_string_view(detail::std_string_view<Char> s) { -+inline auto to_string_view(detail::std_string_view<Char> s) -+ -> basic_string_view<Char> { - return s; - } - -@@ -494,13 +573,15 @@ 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)> --constexpr basic_string_view<typename S::char_type> to_string_view(const S& s) { -- return s; -+constexpr auto to_string_view(const S& s) -+ -> basic_string_view<typename S::char_type> { -+ return basic_string_view<typename S::char_type>(s); - } - --namespace detail { -+FMT_BEGIN_DETAIL_NAMESPACE -+ - void to_string_view(...); --using fmt::v7::to_string_view; -+using fmt::v8::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 -@@ -534,7 +615,7 @@ struct 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 detail -+FMT_END_DETAIL_NAMESPACE - - /** String's character type. */ - template <typename S> using char_t = typename detail::char_t_impl<S>::type; -@@ -543,16 +624,7 @@ template <typename S> using char_t = typename detail::char_t_impl<S>::type; - \rst - Parsing context consisting of a format string range being parsed and an - argument counter for automatic indexing. -- -- You can use one of the following type aliases for common character types: -- -- +-----------------------+-------------------------------------+ -- | Type | Definition | -- +=======================+=====================================+ -- | format_parse_context | basic_format_parse_context<char> | -- +-----------------------+-------------------------------------+ -- | wformat_parse_context | basic_format_parse_context<wchar_t> | -- +-----------------------+-------------------------------------+ -+ You can use the ```format_parse_context`` type alias for ``char`` instead. - \endrst - */ - template <typename Char, typename ErrorHandler = detail::error_handler> -@@ -574,12 +646,16 @@ class basic_format_parse_context : private ErrorHandler { - Returns an iterator to the beginning of the format string range being - parsed. - */ -- constexpr iterator begin() const FMT_NOEXCEPT { return format_str_.begin(); } -+ constexpr auto begin() const FMT_NOEXCEPT -> iterator { -+ return format_str_.begin(); -+ } - - /** - Returns an iterator past the end of the format string range being parsed. - */ -- constexpr iterator end() const FMT_NOEXCEPT { return format_str_.end(); } -+ constexpr auto end() const FMT_NOEXCEPT -> iterator { -+ return format_str_.end(); -+ } - - /** Advances the begin iterator to ``it``. */ - FMT_CONSTEXPR void advance_to(iterator it) { -@@ -590,7 +666,7 @@ class basic_format_parse_context : private ErrorHandler { - Reports an error if using the manual argument indexing; otherwise returns - the next argument index and switches to the automatic indexing. - */ -- FMT_CONSTEXPR int next_arg_id() { -+ FMT_CONSTEXPR auto next_arg_id() -> int { - // Don't check if the argument id is valid to avoid overhead and because it - // will be checked during formatting anyway. - if (next_arg_id_ >= 0) return next_arg_id_++; -@@ -615,11 +691,10 @@ class basic_format_parse_context : private ErrorHandler { - ErrorHandler::on_error(message); - } - -- constexpr ErrorHandler error_handler() const { return *this; } -+ constexpr auto error_handler() const -> ErrorHandler { return *this; } - }; - - using format_parse_context = basic_format_parse_context<char>; --using wformat_parse_context = basic_format_parse_context<wchar_t>; - - template <typename Context> class basic_format_arg; - template <typename Context> class basic_format_args; -@@ -643,11 +718,14 @@ template <typename T> struct is_contiguous : std::false_type {}; - template <typename Char> - struct is_contiguous<std::basic_string<Char>> : std::true_type {}; - --namespace detail { -+class appender; -+ -+FMT_BEGIN_DETAIL_NAMESPACE - - // Extracts a reference to the container from back_insert_iterator. - template <typename Container> --inline Container& get_container(std::back_insert_iterator<Container> it) { -+inline auto get_container(std::back_insert_iterator<Container> it) -+ -> Container& { - using bi_iterator = std::back_insert_iterator<Container>; - struct accessor : bi_iterator { - accessor(bi_iterator iter) : bi_iterator(iter) {} -@@ -656,6 +734,23 @@ inline Container& get_container(std::back_insert_iterator<Container> it) { - return *accessor(it).container; - } - -+template <typename Char, typename InputIt, typename OutputIt> -+FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out) -+ -> OutputIt { -+ while (begin != end) *out++ = static_cast<Char>(*begin++); -+ return out; -+} -+ -+template <typename Char, FMT_ENABLE_IF(std::is_same<Char, char>::value)> -+FMT_CONSTEXPR auto copy_str(const Char* begin, const Char* end, Char* out) -+ -> Char* { -+ if (is_constant_evaluated()) -+ return copy_str<Char, const Char*, Char*>(begin, end, out); -+ auto size = to_unsigned(end - begin); -+ memcpy(out, begin, size); -+ return out + size; -+} -+ - /** - \rst - A contiguous memory buffer with an optional growing ability. It is an internal -@@ -670,7 +765,7 @@ template <typename T> class buffer { - - protected: - // Don't initialize ptr_ since it is not accessed to save a few cycles. -- FMT_SUPPRESS_MSC_WARNING(26495) -+ FMT_MSC_WARNING(suppress : 26495) - buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {} - - buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) FMT_NOEXCEPT -@@ -679,6 +774,7 @@ template <typename T> class buffer { - capacity_(cap) {} - - ~buffer() = default; -+ buffer(buffer&&) = default; - - /** Sets the buffer data and capacity. */ - void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT { -@@ -696,23 +792,23 @@ template <typename T> class buffer { - buffer(const buffer&) = delete; - void operator=(const buffer&) = delete; - -- T* begin() FMT_NOEXCEPT { return ptr_; } -- T* end() FMT_NOEXCEPT { return ptr_ + size_; } -+ auto begin() FMT_NOEXCEPT -> T* { return ptr_; } -+ auto end() FMT_NOEXCEPT -> T* { return ptr_ + size_; } - -- const T* begin() const FMT_NOEXCEPT { return ptr_; } -- const T* end() const FMT_NOEXCEPT { return ptr_ + size_; } -+ auto begin() const FMT_NOEXCEPT -> const T* { return ptr_; } -+ auto end() const FMT_NOEXCEPT -> const T* { return ptr_ + size_; } - - /** Returns the size of this buffer. */ -- size_t size() const FMT_NOEXCEPT { return size_; } -+ auto size() const FMT_NOEXCEPT -> size_t { return size_; } - - /** Returns the capacity of this buffer. */ -- size_t capacity() const FMT_NOEXCEPT { return capacity_; } -+ auto capacity() const FMT_NOEXCEPT -> size_t { return capacity_; } - - /** Returns a pointer to the buffer data. */ -- T* data() FMT_NOEXCEPT { return ptr_; } -+ auto data() FMT_NOEXCEPT -> T* { return ptr_; } - - /** Returns a pointer to the buffer data. */ -- const T* data() const FMT_NOEXCEPT { return ptr_; } -+ auto data() const FMT_NOEXCEPT -> const T* { return ptr_; } - - /** Clears this buffer. */ - void clear() { size_ = 0; } -@@ -740,16 +836,16 @@ template <typename T> class buffer { - /** Appends data to the end of the buffer. */ - template <typename U> void append(const U* begin, const U* end); - -- template <typename I> T& operator[](I index) { return ptr_[index]; } -- template <typename I> const T& operator[](I index) const { -+ template <typename I> auto operator[](I index) -> T& { return ptr_[index]; } -+ template <typename I> auto operator[](I index) const -> const T& { - return ptr_[index]; - } - }; - - struct buffer_traits { - explicit buffer_traits(size_t) {} -- size_t count() const { return 0; } -- size_t limit(size_t size) { return size; } -+ auto count() const -> size_t { return 0; } -+ auto limit(size_t size) -> size_t { return size; } - }; - - class fixed_buffer_traits { -@@ -759,8 +855,8 @@ class fixed_buffer_traits { - - public: - explicit fixed_buffer_traits(size_t limit) : limit_(limit) {} -- size_t count() const { return count_; } -- size_t limit(size_t size) { -+ auto count() const -> size_t { return count_; } -+ auto limit(size_t size) -> size_t { - size_t n = limit_ > count_ ? limit_ - count_ : 0; - count_ += size; - return size < n ? size : n; -@@ -779,20 +875,25 @@ class iterator_buffer final : public Traits, public buffer<T> { - void grow(size_t) final FMT_OVERRIDE { - if (this->size() == buffer_size) flush(); - } -- void flush(); -+ -+ void flush() { -+ auto size = this->size(); -+ this->clear(); -+ out_ = copy_str<T>(data_, data_ + this->limit(size), out_); -+ } - - public: - explicit iterator_buffer(OutputIt out, size_t n = buffer_size) -- : Traits(n), -- buffer<T>(data_, 0, buffer_size), -- out_(out) {} -+ : Traits(n), buffer<T>(data_, 0, buffer_size), out_(out) {} -+ iterator_buffer(iterator_buffer&& other) -+ : Traits(other), buffer<T>(data_, 0, buffer_size), out_(other.out_) {} - ~iterator_buffer() { flush(); } - -- OutputIt out() { -+ auto out() -> OutputIt { - flush(); - return out_; - } -- size_t count() const { return Traits::count() + this->size(); } -+ auto count() const -> size_t { return Traits::count() + this->size(); } - }; - - template <typename T> class iterator_buffer<T*, T> final : public buffer<T> { -@@ -802,7 +903,7 @@ template <typename T> class iterator_buffer<T*, T> final : public buffer<T> { - public: - explicit iterator_buffer(T* out, size_t = 0) : buffer<T>(out, 0, ~size_t()) {} - -- T* out() { return &*this->end(); } -+ auto out() -> T* { return &*this->end(); } - }; - - // A buffer that writes to a container with the contiguous storage. -@@ -825,7 +926,7 @@ class iterator_buffer<std::back_insert_iterator<Container>, - : buffer<typename Container::value_type>(c.size()), container_(c) {} - explicit iterator_buffer(std::back_insert_iterator<Container> out, size_t = 0) - : iterator_buffer(get_container(out)) {} -- std::back_insert_iterator<Container> out() { -+ auto out() -> std::back_insert_iterator<Container> { - return std::back_inserter(container_); - } - }; -@@ -847,48 +948,24 @@ template <typename T = char> class counting_buffer final : public buffer<T> { - public: - counting_buffer() : buffer<T>(data_, 0, buffer_size) {} - -- size_t count() { return count_ + this->size(); } -+ auto count() -> size_t { return count_ + this->size(); } - }; - --// An output iterator that appends to the buffer. --// It is used to reduce symbol sizes for the common case. - template <typename T> --class buffer_appender : public std::back_insert_iterator<buffer<T>> { -- using base = std::back_insert_iterator<buffer<T>>; -- -- public: -- explicit buffer_appender(buffer<T>& buf) : base(buf) {} -- buffer_appender(base it) : base(it) {} -- -- buffer_appender& operator++() { -- base::operator++(); -- return *this; -- } -- -- buffer_appender operator++(int) { -- buffer_appender tmp = *this; -- ++*this; -- return tmp; -- } --}; -+using buffer_appender = conditional_t<std::is_same<T, char>::value, appender, -+ std::back_insert_iterator<buffer<T>>>; - --// Maps an output iterator into a buffer. -+// Maps an output iterator to a buffer. - template <typename T, typename OutputIt> --iterator_buffer<OutputIt, T> get_buffer(OutputIt); --template <typename T> buffer<T>& get_buffer(buffer_appender<T>); -- --template <typename OutputIt> OutputIt get_buffer_init(OutputIt out) { -- return out; --} --template <typename T> buffer<T>& get_buffer_init(buffer_appender<T> out) { -- return get_container(out); -+auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> { -+ return iterator_buffer<OutputIt, T>(out); - } - - template <typename Buffer> - auto get_iterator(Buffer& buf) -> decltype(buf.out()) { - return buf.out(); - } --template <typename T> buffer_appender<T> get_iterator(buffer<T>& buf) { -+template <typename T> auto get_iterator(buffer<T>& buf) -> buffer_appender<T> { - return buffer_appender<T>(buf); - } - -@@ -898,9 +975,9 @@ struct fallback_formatter { - }; - - // Specifies if T has an enabled fallback_formatter specialization. --template <typename T, typename Context> -+template <typename T, typename Char> - using has_fallback_formatter = -- std::is_constructible<fallback_formatter<T, typename Context::char_type>>; -+ std::is_constructible<fallback_formatter<T, Char>>; - - struct view {}; - -@@ -925,8 +1002,8 @@ struct arg_data { - template <typename... U> - arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {} - arg_data(const arg_data& other) = delete; -- const T* args() const { return args_ + 1; } -- named_arg_info<Char>* named_args() { return named_args_; } -+ auto args() const -> const T* { return args_ + 1; } -+ auto named_args() -> named_arg_info<Char>* { return named_args_; } - }; - - template <typename T, typename Char, size_t NUM_ARGS> -@@ -935,42 +1012,47 @@ struct arg_data<T, Char, NUM_ARGS, 0> { - T args_[NUM_ARGS != 0 ? NUM_ARGS : +1]; - - template <typename... U> -- FMT_INLINE arg_data(const U&... init) : args_{init...} {} -- FMT_INLINE const T* args() const { return args_; } -- FMT_INLINE std::nullptr_t named_args() { return nullptr; } -+ FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {} -+ FMT_CONSTEXPR FMT_INLINE auto args() const -> const T* { return args_; } -+ FMT_CONSTEXPR FMT_INLINE auto named_args() -> std::nullptr_t { -+ return nullptr; -+ } - }; - - template <typename Char> - inline void init_named_args(named_arg_info<Char>*, int, int) {} - --template <typename Char, typename T, typename... Tail> -+template <typename T> struct is_named_arg : std::false_type {}; -+template <typename T> struct is_statically_named_arg : std::false_type {}; -+ -+template <typename T, typename Char> -+struct is_named_arg<named_arg<Char, T>> : std::true_type {}; -+ -+template <typename Char, typename T, typename... Tail, -+ FMT_ENABLE_IF(!is_named_arg<T>::value)> - void init_named_args(named_arg_info<Char>* named_args, int arg_count, - int named_arg_count, const T&, const Tail&... args) { - init_named_args(named_args, arg_count + 1, named_arg_count, args...); - } - --template <typename Char, typename T, typename... Tail> -+template <typename Char, typename T, typename... Tail, -+ FMT_ENABLE_IF(is_named_arg<T>::value)> - void init_named_args(named_arg_info<Char>* named_args, int arg_count, -- int named_arg_count, const named_arg<Char, T>& arg, -- const Tail&... args) { -+ int named_arg_count, const T& arg, const Tail&... args) { - named_args[named_arg_count++] = {arg.name, arg_count}; - init_named_args(named_args, arg_count + 1, named_arg_count, args...); - } - - template <typename... Args> --FMT_INLINE void init_named_args(std::nullptr_t, int, int, const Args&...) {} -- --template <typename T> struct is_named_arg : std::false_type {}; -- --template <typename T, typename Char> --struct is_named_arg<named_arg<Char, T>> : std::true_type {}; -+FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int, -+ const Args&...) {} - --template <bool B = false> constexpr size_t count() { return B ? 1 : 0; } --template <bool B1, bool B2, bool... Tail> constexpr size_t count() { -+template <bool B = false> constexpr auto count() -> size_t { return B ? 1 : 0; } -+template <bool B1, bool B2, bool... Tail> constexpr auto count() -> size_t { - return (B1 ? 1 : 0) + count<B2, Tail...>(); - } - --template <typename... Args> constexpr size_t count_named_args() { -+template <typename... Args> constexpr auto count_named_args() -> size_t { - return count<is_named_arg<Args>::value...>(); - } - -@@ -1051,6 +1133,7 @@ template <typename Context> class value { - using char_type = typename Context::char_type; - - union { -+ monostate no_value; - int int_value; - unsigned uint_value; - long long long_long_value; -@@ -1068,19 +1151,23 @@ template <typename Context> class value { - named_arg_value<char_type> named_args; - }; - -- constexpr FMT_INLINE value(int val = 0) : int_value(val) {} -+ constexpr FMT_INLINE value() : no_value() {} -+ constexpr FMT_INLINE value(int val) : int_value(val) {} - constexpr FMT_INLINE value(unsigned val) : uint_value(val) {} -- FMT_INLINE value(long long val) : long_long_value(val) {} -- FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {} -+ constexpr FMT_INLINE value(long long val) : long_long_value(val) {} -+ constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {} - FMT_INLINE value(int128_t val) : int128_value(val) {} - FMT_INLINE value(uint128_t val) : uint128_value(val) {} - FMT_INLINE value(float val) : float_value(val) {} - FMT_INLINE value(double val) : double_value(val) {} - FMT_INLINE value(long double val) : long_double_value(val) {} -- FMT_INLINE value(bool val) : bool_value(val) {} -- FMT_INLINE value(char_type val) : char_value(val) {} -- FMT_INLINE value(const char_type* val) { string.data = val; } -- FMT_INLINE value(basic_string_view<char_type> val) { -+ constexpr FMT_INLINE value(bool val) : bool_value(val) {} -+ constexpr FMT_INLINE value(char_type val) : char_value(val) {} -+ FMT_CONSTEXPR FMT_INLINE value(const char_type* val) { -+ string.data = val; -+ if (is_constant_evaluated()) string.size = {}; -+ } -+ FMT_CONSTEXPR FMT_INLINE value(basic_string_view<char_type> val) { - string.data = val.data(); - string.size = val.size(); - } -@@ -1088,7 +1175,7 @@ template <typename Context> class value { - FMT_INLINE value(const named_arg_info<char_type>* args, size_t size) - : named_args{args, size} {} - -- template <typename T> FMT_INLINE value(const T& val) { -+ template <typename T> FMT_CONSTEXPR FMT_INLINE 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 -@@ -1112,7 +1199,7 @@ template <typename Context> class value { - }; - - template <typename Context, typename T> --FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value); -+FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context>; - - // 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. -@@ -1126,36 +1213,52 @@ struct unformattable {}; - 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 int128_t map(int128_t val) { return val; } -- FMT_CONSTEXPR uint128_t map(uint128_t val) { return val; } -- FMT_CONSTEXPR bool map(bool val) { return val; } -+ FMT_CONSTEXPR FMT_INLINE auto map(signed char val) -> int { return val; } -+ FMT_CONSTEXPR FMT_INLINE auto map(unsigned char val) -> unsigned { -+ return val; -+ } -+ FMT_CONSTEXPR FMT_INLINE auto map(short val) -> int { return val; } -+ FMT_CONSTEXPR FMT_INLINE auto map(unsigned short val) -> unsigned { -+ return val; -+ } -+ FMT_CONSTEXPR FMT_INLINE auto map(int val) -> int { return val; } -+ FMT_CONSTEXPR FMT_INLINE auto map(unsigned val) -> unsigned { return val; } -+ FMT_CONSTEXPR FMT_INLINE auto map(long val) -> long_type { return val; } -+ FMT_CONSTEXPR FMT_INLINE auto map(unsigned long val) -> ulong_type { -+ return val; -+ } -+ FMT_CONSTEXPR FMT_INLINE auto map(long long val) -> long long { return val; } -+ FMT_CONSTEXPR FMT_INLINE auto map(unsigned long long val) -+ -> unsigned long long { -+ return val; -+ } -+ FMT_CONSTEXPR FMT_INLINE auto map(int128_t val) -> int128_t { return val; } -+ FMT_CONSTEXPR FMT_INLINE auto map(uint128_t val) -> uint128_t { return val; } -+ FMT_CONSTEXPR FMT_INLINE auto map(bool val) -> bool { return val; } - - template <typename T, FMT_ENABLE_IF(is_char<T>::value)> -- FMT_CONSTEXPR char_type map(T val) { -+ FMT_CONSTEXPR FMT_INLINE auto map(T val) -> char_type { - static_assert( - std::is_same<T, char>::value || std::is_same<T, char_type>::value, - "mixing character types is disallowed"); - return val; - } - -- FMT_CONSTEXPR float map(float val) { return val; } -- FMT_CONSTEXPR double map(double val) { return val; } -- FMT_CONSTEXPR long double map(long double val) { return val; } -+ FMT_CONSTEXPR FMT_INLINE auto map(float val) -> float { return val; } -+ FMT_CONSTEXPR FMT_INLINE auto map(double val) -> double { return val; } -+ FMT_CONSTEXPR FMT_INLINE auto map(long double val) -> long double { -+ 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; } -+ FMT_CONSTEXPR FMT_INLINE auto map(char_type* val) -> const char_type* { -+ return val; -+ } -+ FMT_CONSTEXPR FMT_INLINE auto map(const char_type* val) -> const char_type* { -+ return val; -+ } - template <typename T, FMT_ENABLE_IF(is_string<T>::value)> -- FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) { -+ FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -+ -> basic_string_view<char_type> { - static_assert(std::is_same<char_type, char_t<T>>::value, - "mixing character types is disallowed"); - return to_string_view(val); -@@ -1164,8 +1267,9 @@ template <typename Context> struct arg_mapper { - FMT_ENABLE_IF( - std::is_constructible<basic_string_view<char_type>, T>::value && - !is_string<T>::value && !has_formatter<T, Context>::value && -- !has_fallback_formatter<T, Context>::value)> -- FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) { -+ !has_fallback_formatter<T, char_type>::value)> -+ FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -+ -> basic_string_view<char_type> { - return basic_string_view<char_type>(val); - } - template < -@@ -1174,31 +1278,40 @@ template <typename Context> struct arg_mapper { - std::is_constructible<std_string_view<char_type>, T>::value && - !std::is_constructible<basic_string_view<char_type>, T>::value && - !is_string<T>::value && !has_formatter<T, Context>::value && -- !has_fallback_formatter<T, Context>::value)> -- FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) { -+ !has_fallback_formatter<T, char_type>::value)> -+ FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -+ -> basic_string_view<char_type> { - return std_string_view<char_type>(val); - } -- FMT_CONSTEXPR const char* map(const signed char* val) { -+ FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val) -> const char* { - 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) { -+ FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val) -> const char* { - static_assert(std::is_same<char_type, char>::value, "invalid string type"); - return reinterpret_cast<const char*>(val); - } -- FMT_CONSTEXPR const char* map(signed char* val) { -+ FMT_CONSTEXPR FMT_INLINE auto map(signed char* val) -> const char* { - const auto* const_val = val; - return map(const_val); - } -- FMT_CONSTEXPR const char* map(unsigned char* val) { -+ FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val) -> const char* { - const auto* const_val = val; - return map(const_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*) { -+ FMT_CONSTEXPR FMT_INLINE auto map(void* val) -> const void* { return val; } -+ FMT_CONSTEXPR FMT_INLINE auto map(const void* val) -> const void* { -+ return val; -+ } -+ FMT_CONSTEXPR FMT_INLINE auto map(std::nullptr_t val) -> const void* { -+ return val; -+ } -+ -+ // We use SFINAE instead of a const T* parameter to avoid conflicting with -+ // the C array overload. -+ template <typename T> -+ FMT_CONSTEXPR auto map(T) -> enable_if_t<std::is_pointer<T>::value, int> { - // 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 -@@ -1207,11 +1320,16 @@ template <typename Context> struct arg_mapper { - return 0; - } - -+ template <typename T, std::size_t N> -+ FMT_CONSTEXPR FMT_INLINE auto map(const T (&values)[N]) -> const T (&)[N] { -+ return values; -+ } -+ - template <typename T, - FMT_ENABLE_IF(std::is_enum<T>::value && - !has_formatter<T, Context>::value && -- !has_fallback_formatter<T, Context>::value)> -- FMT_CONSTEXPR auto map(const T& val) -+ !has_fallback_formatter<T, char_type>::value)> -+ FMT_CONSTEXPR FMT_INLINE auto map(const T& val) - -> decltype(std::declval<arg_mapper>().map( - static_cast<typename std::underlying_type<T>::type>(val))) { - return map(static_cast<typename std::underlying_type<T>::type>(val)); -@@ -1219,18 +1337,18 @@ template <typename Context> struct arg_mapper { - 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) { -+ has_fallback_formatter<T, char_type>::value))> -+ FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> const T& { - return val; - } - -- template <typename T> -- FMT_CONSTEXPR auto map(const named_arg<char_type, T>& val) -- -> decltype(std::declval<arg_mapper>().map(val.value)) { -- return map(val.value); -+ template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)> -+ FMT_CONSTEXPR FMT_INLINE auto map(const T& named_arg) -+ -> decltype(std::declval<arg_mapper>().map(named_arg.value)) { -+ return map(named_arg.value); - } - -- unformattable map(...) { return {}; } -+ auto map(...) -> unformattable { return {}; } - }; - - // A type constant after applying arg_mapper<Context>. -@@ -1244,7 +1362,35 @@ enum { packed_arg_bits = 4 }; - enum { max_packed_args = 62 / packed_arg_bits }; - enum : unsigned long long { is_unpacked_bit = 1ULL << 63 }; - enum : unsigned long long { has_named_args_bit = 1ULL << 62 }; --} // namespace detail -+ -+FMT_END_DETAIL_NAMESPACE -+ -+// An output iterator that appends to a buffer. -+// It is used to reduce symbol sizes for the common case. -+class appender : public std::back_insert_iterator<detail::buffer<char>> { -+ using base = std::back_insert_iterator<detail::buffer<char>>; -+ -+ template <typename T> -+ friend auto get_buffer(appender out) -> detail::buffer<char>& { -+ return detail::get_container(out); -+ } -+ -+ public: -+ using std::back_insert_iterator<detail::buffer<char>>::back_insert_iterator; -+ appender(base it) : base(it) {} -+ using _Unchecked_type = appender; // Mark iterator as checked. -+ -+ auto operator++() -> appender& { -+ base::operator++(); -+ return *this; -+ } -+ -+ auto operator++(int) -> appender { -+ auto tmp = *this; -+ ++*this; -+ return tmp; -+ } -+}; - - // A formatting argument. It is a trivially copyable/constructible type to - // allow storage in basic_memory_buffer. -@@ -1254,8 +1400,8 @@ template <typename Context> class basic_format_arg { - detail::type type_; - - template <typename ContextType, typename T> -- friend FMT_CONSTEXPR basic_format_arg<ContextType> detail::make_arg( -- const T& value); -+ friend FMT_CONSTEXPR auto detail::make_arg(const T& value) -+ -> basic_format_arg<ContextType>; - - template <typename Visitor, typename Ctx> - friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis, -@@ -1293,10 +1439,12 @@ template <typename Context> class basic_format_arg { - return type_ != detail::type::none_type; - } - -- detail::type type() const { return type_; } -+ auto type() const -> detail::type { return type_; } - -- bool is_integral() const { return detail::is_integral_type(type_); } -- bool is_arithmetic() const { return detail::is_arithmetic_type(type_); } -+ auto is_integral() const -> bool { return detail::is_integral_type(type_); } -+ auto is_arithmetic() const -> bool { -+ return detail::is_arithmetic_type(type_); -+ } - }; - - /** -@@ -1307,9 +1455,8 @@ template <typename Context> class basic_format_arg { - \endrst - */ - template <typename Visitor, typename Context> --FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg( -+FMT_CONSTEXPR FMT_INLINE 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 detail::type::none_type: - break; -@@ -1321,16 +1468,10 @@ FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg( - return vis(arg.value_.long_long_value); - case detail::type::ulong_long_type: - return vis(arg.value_.ulong_long_value); --#if FMT_USE_INT128 -- case detail::type::int128_type: -- return vis(arg.value_.int128_value); -- case detail::type::uint128_type: -- return vis(arg.value_.uint128_value); --#else - case detail::type::int128_type: -+ return vis(detail::convert_for_visit(arg.value_.int128_value)); - case detail::type::uint128_type: -- break; --#endif -+ return vis(detail::convert_for_visit(arg.value_.uint128_value)); - case detail::type::bool_type: - return vis(arg.value_.bool_value); - case detail::type::char_type: -@@ -1344,8 +1485,8 @@ FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg( - case detail::type::cstring_type: - return vis(arg.value_.string.data); - case detail::type::string_type: -- return vis(basic_string_view<char_type>(arg.value_.string.data, -- arg.value_.string.size)); -+ using sv = basic_string_view<typename Context::char_type>; -+ return vis(sv(arg.value_.string.data, arg.value_.string.size)); - case detail::type::pointer_type: - return vis(arg.value_.pointer); - case detail::type::custom_type: -@@ -1354,14 +1495,22 @@ FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg( - return vis(monostate()); - } - --template <typename T> struct formattable : std::false_type {}; -+FMT_BEGIN_DETAIL_NAMESPACE - --namespace detail { -+template <typename Char, typename InputIt> -+auto copy_str(InputIt begin, InputIt end, appender out) -> appender { -+ get_container(out).append(begin, end); -+ return out; -+} - -+#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 - // A workaround for gcc 4.8 to make void_t work in a SFINAE context. - template <typename... Ts> struct void_t_impl { using type = void; }; - template <typename... Ts> - using void_t = typename detail::void_t_impl<Ts...>::type; -+#else -+template <typename...> using void_t = void; -+#endif - - template <typename It, typename T, typename Enable = void> - struct is_output_iterator : std::false_type {}; -@@ -1384,9 +1533,8 @@ 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 is_contiguous_back_insert_iterator<buffer_appender<Char>> -- : std::true_type {}; -+template <> -+struct is_contiguous_back_insert_iterator<appender> : std::true_type {}; - - // A type-erased reference to an std::locale to avoid heavy <locale> include. - class locale_ref { -@@ -1394,97 +1542,52 @@ class locale_ref { - const void* locale_; // A type-erased pointer to std::locale. - - public: -- locale_ref() : locale_(nullptr) {} -+ constexpr locale_ref() : locale_(nullptr) {} - template <typename Locale> explicit locale_ref(const Locale& loc); - - explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; } - -- template <typename Locale> Locale get() const; -+ template <typename Locale> auto get() const -> Locale; - }; - --template <typename> constexpr unsigned long long encode_types() { return 0; } -+template <typename> constexpr auto encode_types() -> unsigned long long { -+ return 0; -+} - - template <typename Context, typename Arg, typename... Args> --constexpr unsigned long long encode_types() { -+constexpr auto encode_types() -> unsigned long long { - return static_cast<unsigned>(mapped_type_constant<Arg, Context>::value) | - (encode_types<Context, Args...>() << packed_arg_bits); - } - - template <typename Context, typename T> --FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value) { -+FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context> { - basic_format_arg<Context> arg; - arg.type_ = mapped_type_constant<T, Context>::value; - arg.value_ = arg_mapper<Context>().map(value); - return arg; - } - --template <typename T> int check(unformattable) { -- static_assert( -- formattable<T>(), -- "Cannot format an argument. To make type T formattable provide a " -- "formatter<T> specialization: https://fmt.dev/latest/api.html#udt"); -- return 0; --} --template <typename T, typename U> inline const U& check(const U& val) { -- return val; --} -- - // The type template parameter is there to avoid an ODR violation when using - // a fallback formatter in one translation unit and an implicit conversion in - // another (not recommended). - template <bool IS_PACKED, typename Context, type, typename T, - FMT_ENABLE_IF(IS_PACKED)> --inline value<Context> make_arg(const T& val) { -- return check<T>(arg_mapper<Context>().map(val)); -+FMT_CONSTEXPR FMT_INLINE auto make_arg(const T& val) -> value<Context> { -+ const auto& arg = arg_mapper<Context>().map(val); -+ static_assert( -+ !std::is_same<decltype(arg), const unformattable&>::value, -+ "Cannot format an argument. To make type T formattable provide a " -+ "formatter<T> specialization: https://fmt.dev/latest/api.html#udt"); -+ return {arg}; - } - - template <bool IS_PACKED, typename Context, type, typename T, - FMT_ENABLE_IF(!IS_PACKED)> --inline basic_format_arg<Context> make_arg(const T& value) { -+inline auto make_arg(const T& value) -> basic_format_arg<Context> { - return make_arg<Context>(value); - } -- --template <typename T> struct is_reference_wrapper : std::false_type {}; --template <typename T> --struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; -- --template <typename T> const T& unwrap(const T& v) { return v; } --template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) { -- return static_cast<const T&>(v); --} -- --class dynamic_arg_list { -- // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for -- // templates it doesn't complain about inability to deduce single translation -- // unit for placing vtable. So storage_node_base is made a fake template. -- template <typename = void> struct node { -- virtual ~node() = default; -- std::unique_ptr<node<>> next; -- }; -- -- template <typename T> struct typed_node : node<> { -- T value; -- -- template <typename Arg> -- FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} -- -- template <typename Char> -- FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg) -- : value(arg.data(), arg.size()) {} -- }; -- -- std::unique_ptr<node<>> head_; -- -- public: -- template <typename T, typename Arg> const T& push(const Arg& arg) { -- auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg)); -- auto& value = new_node->value; -- new_node->next = std::move(head_); -- head_ = std::move(new_node); -- return value; -- } --}; --} // namespace detail -+FMT_END_DETAIL_NAMESPACE - - // Formatting context. - template <typename OutputIt, typename Char> class basic_format_context { -@@ -1503,46 +1606,59 @@ template <typename OutputIt, typename Char> class basic_format_context { - using parse_context_type = basic_format_parse_context<Char>; - template <typename T> using formatter_type = formatter<T, char_type>; - -+ basic_format_context(basic_format_context&&) = default; - basic_format_context(const basic_format_context&) = delete; - void operator=(const basic_format_context&) = delete; - /** - Constructs a ``basic_format_context`` object. References to the arguments are - stored in the object so make sure they have appropriate lifetimes. - */ -- basic_format_context(OutputIt out, -- basic_format_args<basic_format_context> ctx_args, -- detail::locale_ref loc = detail::locale_ref()) -+ constexpr basic_format_context( -+ OutputIt out, basic_format_args<basic_format_context> ctx_args, -+ detail::locale_ref loc = detail::locale_ref()) - : out_(out), args_(ctx_args), loc_(loc) {} - -- format_arg arg(int id) const { return args_.get(id); } -- format_arg arg(basic_string_view<char_type> name) { return args_.get(name); } -- int arg_id(basic_string_view<char_type> name) { return args_.get_id(name); } -- const basic_format_args<basic_format_context>& args() const { return args_; } -+ constexpr auto arg(int id) const -> format_arg { return args_.get(id); } -+ FMT_CONSTEXPR auto arg(basic_string_view<char_type> name) -> format_arg { -+ return args_.get(name); -+ } -+ FMT_CONSTEXPR auto arg_id(basic_string_view<char_type> name) -> int { -+ return args_.get_id(name); -+ } -+ auto args() const -> const basic_format_args<basic_format_context>& { -+ return args_; -+ } - -- detail::error_handler error_handler() { return {}; } -+ FMT_CONSTEXPR auto error_handler() -> detail::error_handler { return {}; } - void on_error(const char* message) { error_handler().on_error(message); } - - // Returns an iterator to the beginning of the output range. -- iterator out() { return out_; } -+ FMT_CONSTEXPR auto out() -> iterator { return out_; } - - // Advances the begin iterator to ``it``. - void advance_to(iterator it) { - if (!detail::is_back_insert_iterator<iterator>()) out_ = it; - } - -- detail::locale_ref locale() { return loc_; } -+ FMT_CONSTEXPR auto locale() -> detail::locale_ref { return loc_; } - }; - - template <typename Char> - using buffer_context = - basic_format_context<detail::buffer_appender<Char>, Char>; - using format_context = buffer_context<char>; --using wformat_context = buffer_context<wchar_t>; - - // Workaround an alias issue: https://stackoverflow.com/q/62767544/471164. - #define FMT_BUFFER_CONTEXT(Char) \ - basic_format_context<detail::buffer_appender<Char>, Char> - -+template <typename T, typename Char = char> -+using is_formattable = bool_constant< -+ !std::is_same<decltype(detail::arg_mapper<buffer_context<Char>>().map( -+ std::declval<T>())), -+ detail::unformattable>::value && -+ !detail::has_fallback_formatter<T, Char>::value>; -+ - /** - \rst - An array of references to arguments. It can be implicitly converted into -@@ -1579,7 +1695,7 @@ class format_arg_store - : 0); - - public: -- format_arg_store(const Args&... args) -+ FMT_CONSTEXPR FMT_INLINE format_arg_store(const Args&... args) - : - #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 - basic_format_args<Context>(*this), -@@ -1600,36 +1716,16 @@ class format_arg_store - \endrst - */ - template <typename Context = format_context, typename... Args> --inline format_arg_store<Context, Args...> make_format_args( -- const Args&... args) { -- return {args...}; --} -- --/** -- \rst -- Constructs a `~fmt::format_arg_store` object that contains references -- to arguments and can be implicitly converted to `~fmt::format_args`. -- If ``format_str`` is a compile-time string then `make_args_checked` checks -- its validity at compile time. -- \endrst -- */ --template <typename... Args, typename S, typename Char = char_t<S>> --inline auto make_args_checked(const S& format_str, -- const remove_reference_t<Args>&... args) -- -> format_arg_store<buffer_context<Char>, remove_reference_t<Args>...> { -- static_assert( -- detail::count<( -- std::is_base_of<detail::view, remove_reference_t<Args>>::value && -- std::is_reference<Args>::value)...>() == 0, -- "passing views as lvalues is disallowed"); -- detail::check_format_string<Args...>(format_str); -+constexpr auto make_format_args(const Args&... args) -+ -> format_arg_store<Context, Args...> { - return {args...}; - } - - /** - \rst -- Returns a named argument to be used in a formatting function. It should only -- be used in a call to a formatting function. -+ Returns a named argument to be used in a formatting function. -+ It should only be used in a call to a formatting function or -+ `dynamic_format_arg_store::push_back`. - - **Example**:: - -@@ -1637,243 +1733,74 @@ inline auto make_args_checked(const S& format_str, - \endrst - */ - template <typename Char, typename T> --inline detail::named_arg<Char, T> arg(const Char* name, const T& arg) { -+inline auto arg(const Char* name, const T& arg) -> detail::named_arg<Char, T> { - static_assert(!detail::is_named_arg<T>(), "nested named arguments"); - return {name, arg}; - } - - /** - \rst -- A dynamic version of `fmt::format_arg_store`. -- It's equipped with a storage to potentially temporary objects which lifetimes -- could be shorter than the format arguments object. -+ A view of a collection of formatting arguments. To avoid lifetime issues it -+ should only be used as a parameter type in type-erased functions such as -+ ``vformat``:: - -- It can be implicitly converted into `~fmt::basic_format_args` for passing -- into type-erased formatting functions such as `~fmt::vformat`. -+ void vlog(string_view format_str, format_args args); // OK -+ format_args args = make_format_args(42); // Error: dangling reference - \endrst - */ --template <typename Context> --class dynamic_format_arg_store --#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 -- // Workaround a GCC template argument substitution bug. -- : public basic_format_args<Context> --#endif --{ -- private: -- using char_type = typename Context::char_type; -+template <typename Context> class basic_format_args { -+ public: -+ using size_type = int; -+ using format_arg = basic_format_arg<Context>; - -- template <typename T> struct need_copy { -- static constexpr detail::type mapped_type = -- detail::mapped_type_constant<T, Context>::value; -- -- enum { -- value = !(detail::is_reference_wrapper<T>::value || -- std::is_same<T, basic_string_view<char_type>>::value || -- std::is_same<T, detail::std_string_view<char_type>>::value || -- (mapped_type != detail::type::cstring_type && -- mapped_type != detail::type::string_type && -- mapped_type != detail::type::custom_type)) -- }; -+ private: -+ // A descriptor that contains information about formatting arguments. -+ // If the number of arguments is less or equal to max_packed_args then -+ // argument types are passed in the descriptor. This reduces binary code size -+ // per formatting function call. -+ unsigned long long desc_; -+ union { -+ // If is_packed() returns true then argument values are stored in values_; -+ // otherwise they are stored in args_. This is done to improve cache -+ // locality and reduce compiled code size since storing larger objects -+ // may require more code (at least on x86-64) even if the same amount of -+ // data is actually copied to stack. It saves ~10% on the bloat test. -+ const detail::value<Context>* values_; -+ const format_arg* args_; - }; - -- template <typename T> -- using stored_type = conditional_t<detail::is_string<T>::value, -- std::basic_string<char_type>, T>; -- -- // Storage of basic_format_arg must be contiguous. -- std::vector<basic_format_arg<Context>> data_; -- std::vector<detail::named_arg_info<char_type>> named_info_; -- -- // Storage of arguments not fitting into basic_format_arg must grow -- // without relocation because items in data_ refer to it. -- detail::dynamic_arg_list dynamic_args_; -- -- friend class basic_format_args<Context>; -- -- unsigned long long get_types() const { -- return detail::is_unpacked_bit | data_.size() | -- (named_info_.empty() -- ? 0ULL -- : static_cast<unsigned long long>(detail::has_named_args_bit)); -+ constexpr auto is_packed() const -> bool { -+ return (desc_ & detail::is_unpacked_bit) == 0; - } -- -- const basic_format_arg<Context>* data() const { -- return named_info_.empty() ? data_.data() : data_.data() + 1; -+ auto has_named_args() const -> bool { -+ return (desc_ & detail::has_named_args_bit) != 0; - } - -- template <typename T> void emplace_arg(const T& arg) { -- data_.emplace_back(detail::make_arg<Context>(arg)); -+ FMT_CONSTEXPR auto type(int index) const -> detail::type { -+ int shift = index * detail::packed_arg_bits; -+ unsigned int mask = (1 << detail::packed_arg_bits) - 1; -+ return static_cast<detail::type>((desc_ >> shift) & mask); - } - -- template <typename T> -- void emplace_arg(const detail::named_arg<char_type, T>& arg) { -- if (named_info_.empty()) { -- constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr}; -- data_.insert(data_.begin(), {zero_ptr, 0}); -- } -- data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value))); -- auto pop_one = [](std::vector<basic_format_arg<Context>>* data) { -- data->pop_back(); -- }; -- std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)> -- guard{&data_, pop_one}; -- named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)}); -- data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; -- guard.release(); -- } -+ constexpr FMT_INLINE basic_format_args(unsigned long long desc, -+ const detail::value<Context>* values) -+ : desc_(desc), values_(values) {} -+ constexpr basic_format_args(unsigned long long desc, const format_arg* args) -+ : desc_(desc), args_(args) {} - - public: -- /** -- \rst -- Adds an argument into the dynamic store for later passing to a formatting -- function. -- -- Note that custom types and string types (but not string views) are copied -- into the store dynamically allocating memory if necessary. -- -- **Example**:: -- -- fmt::dynamic_format_arg_store<fmt::format_context> store; -- store.push_back(42); -- store.push_back("abc"); -- store.push_back(1.5f); -- std::string result = fmt::vformat("{} and {} and {}", store); -- \endrst -- */ -- template <typename T> void push_back(const T& arg) { -- if (detail::const_check(need_copy<T>::value)) -- emplace_arg(dynamic_args_.push<stored_type<T>>(arg)); -- else -- emplace_arg(detail::unwrap(arg)); -- } -+ constexpr basic_format_args() : desc_(0), args_(nullptr) {} - - /** -- \rst -- Adds a reference to the argument into the dynamic store for later passing to -- a formatting function. Supports named arguments wrapped in -- ``std::reference_wrapper`` via ``std::ref()``/``std::cref()``. -- -- **Example**:: -- -- fmt::dynamic_format_arg_store<fmt::format_context> store; -- char str[] = "1234567890"; -- store.push_back(std::cref(str)); -- int a1_val{42}; -- auto a1 = fmt::arg("a1_", a1_val); -- store.push_back(std::cref(a1)); -- -- // Changing str affects the output but only for string and custom types. -- str[0] = 'X'; -- -- std::string result = fmt::vformat("{} and {a1_}"); -- assert(result == "X234567890 and 42"); -- \endrst -- */ -- template <typename T> void push_back(std::reference_wrapper<T> arg) { -- static_assert( -- detail::is_named_arg<typename std::remove_cv<T>::type>::value || -- need_copy<T>::value, -- "objects of built-in types and string views are always copied"); -- emplace_arg(arg.get()); -- } -- -- /** -- Adds named argument into the dynamic store for later passing to a formatting -- function. ``std::reference_wrapper`` is supported to avoid copying of the -- argument. -- */ -- template <typename T> -- void push_back(const detail::named_arg<char_type, T>& arg) { -- const char_type* arg_name = -- dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str(); -- if (detail::const_check(need_copy<T>::value)) { -- emplace_arg( -- fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value))); -- } else { -- emplace_arg(fmt::arg(arg_name, arg.value)); -- } -- } -- -- /** Erase all elements from the store */ -- void clear() { -- data_.clear(); -- named_info_.clear(); -- dynamic_args_ = detail::dynamic_arg_list(); -- } -- -- /** -- \rst -- Reserves space to store at least *new_cap* arguments including -- *new_cap_named* named arguments. -- \endrst -- */ -- void reserve(size_t new_cap, size_t new_cap_named) { -- FMT_ASSERT(new_cap >= new_cap_named, -- "Set of arguments includes set of named arguments"); -- data_.reserve(new_cap); -- named_info_.reserve(new_cap_named); -- } --}; -- --/** -- \rst -- A view of a collection of formatting arguments. To avoid lifetime issues it -- should only be used as a parameter type in type-erased functions such as -- ``vformat``:: -- -- void vlog(string_view format_str, format_args args); // OK -- format_args args = make_format_args(42); // Error: dangling reference -- \endrst -- */ --template <typename Context> class basic_format_args { -- public: -- using size_type = int; -- using format_arg = basic_format_arg<Context>; -- -- private: -- // A descriptor that contains information about formatting arguments. -- // If the number of arguments is less or equal to max_packed_args then -- // argument types are passed in the descriptor. This reduces binary code size -- // per formatting function call. -- unsigned long long desc_; -- union { -- // If is_packed() returns true then argument values are stored in values_; -- // otherwise they are stored in args_. This is done to improve cache -- // locality and reduce compiled code size since storing larger objects -- // may require more code (at least on x86-64) even if the same amount of -- // data is actually copied to stack. It saves ~10% on the bloat test. -- const detail::value<Context>* values_; -- const format_arg* args_; -- }; -- -- bool is_packed() const { return (desc_ & detail::is_unpacked_bit) == 0; } -- bool has_named_args() const { -- return (desc_ & detail::has_named_args_bit) != 0; -- } -- -- detail::type type(int index) const { -- int shift = index * detail::packed_arg_bits; -- unsigned int mask = (1 << detail::packed_arg_bits) - 1; -- return static_cast<detail::type>((desc_ >> shift) & mask); -- } -- -- basic_format_args(unsigned long long desc, -- const detail::value<Context>* values) -- : desc_(desc), values_(values) {} -- basic_format_args(unsigned long long desc, const format_arg* args) -- : desc_(desc), args_(args) {} -- -- public: -- basic_format_args() : desc_(0) {} -- -- /** -- \rst -- Constructs a `basic_format_args` object from `~fmt::format_arg_store`. -- \endrst -- */ -- template <typename... Args> -- FMT_INLINE basic_format_args(const format_arg_store<Context, Args...>& store) -- : basic_format_args(store.desc, store.data_.args()) {} -+ \rst -+ Constructs a `basic_format_args` object from `~fmt::format_arg_store`. -+ \endrst -+ */ -+ template <typename... Args> -+ constexpr FMT_INLINE basic_format_args( -+ const format_arg_store<Context, Args...>& store) -+ : basic_format_args(format_arg_store<Context, Args...>::desc, -+ store.data_.args()) {} - - /** - \rst -@@ -1881,7 +1808,8 @@ template <typename Context> class basic_format_args { - `~fmt::dynamic_format_arg_store`. - \endrst - */ -- FMT_INLINE basic_format_args(const dynamic_format_arg_store<Context>& store) -+ constexpr FMT_INLINE basic_format_args( -+ const dynamic_format_arg_store<Context>& store) - : basic_format_args(store.get_types(), store.data()) {} - - /** -@@ -1889,12 +1817,12 @@ template <typename Context> class basic_format_args { - Constructs a `basic_format_args` object from a dynamic set of arguments. - \endrst - */ -- basic_format_args(const format_arg* args, int count) -+ constexpr basic_format_args(const format_arg* args, int count) - : basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count), - args) {} - - /** Returns the argument with the specified id. */ -- format_arg get(int id) const { -+ FMT_CONSTEXPR auto get(int id) const -> format_arg { - format_arg arg; - if (!is_packed()) { - if (id < max_size()) arg = args_[id]; -@@ -1907,12 +1835,14 @@ template <typename Context> class basic_format_args { - return arg; - } - -- template <typename Char> format_arg get(basic_string_view<Char> name) const { -+ template <typename Char> -+ auto get(basic_string_view<Char> name) const -> format_arg { - int id = get_id(name); - return id >= 0 ? get(id) : format_arg(); - } - -- template <typename Char> int get_id(basic_string_view<Char> name) const { -+ template <typename Char> -+ auto get_id(basic_string_view<Char> name) const -> int { - if (!has_named_args()) return -1; - const auto& named_args = - (is_packed() ? values_[-1] : args_[-1].value_).named_args; -@@ -1922,87 +1852,1071 @@ template <typename Context> class basic_format_args { - return -1; - } - -- int max_size() const { -+ auto max_size() const -> int { - unsigned long long max_packed = detail::max_packed_args; - return static_cast<int>(is_packed() ? max_packed - : desc_ & ~detail::is_unpacked_bit); - } - }; - --#ifdef FMT_ARM_ABI_COMPATIBILITY - /** An alias to ``basic_format_args<format_context>``. */ --// Separate types would result in shorter symbols but break ABI compatibility -+// A separate type would result in shorter symbols but break ABI compatibility - // between clang and gcc on ARM (#1919). - using format_args = basic_format_args<format_context>; --using wformat_args = basic_format_args<wformat_context>; --#else --// DEPRECATED! These are kept for ABI compatibility. --// It is a separate type rather than an alias to make symbols readable. --struct format_args : basic_format_args<format_context> { -- template <typename... Args> -- FMT_INLINE format_args(const Args&... args) : basic_format_args(args...) {} -+ -+// We cannot use enum classes as bit fields because of a gcc bug -+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414. -+namespace align { -+enum type { none, left, right, center, numeric }; -+} -+using align_t = align::type; -+namespace sign { -+enum type { none, minus, plus, space }; -+} -+using sign_t = sign::type; -+ -+FMT_BEGIN_DETAIL_NAMESPACE -+ -+void throw_format_error(const char* message); -+ -+// Workaround an array initialization issue in gcc 4.8. -+template <typename Char> struct fill_t { -+ private: -+ enum { max_size = 4 }; -+ Char data_[max_size] = {Char(' '), Char(0), Char(0), Char(0)}; -+ unsigned char size_ = 1; -+ -+ public: -+ FMT_CONSTEXPR void operator=(basic_string_view<Char> s) { -+ auto size = s.size(); -+ if (size > max_size) return throw_format_error("invalid fill"); -+ for (size_t i = 0; i < size; ++i) data_[i] = s[i]; -+ size_ = static_cast<unsigned char>(size); -+ } -+ -+ constexpr auto size() const -> size_t { return size_; } -+ constexpr auto data() const -> const Char* { return data_; } -+ -+ FMT_CONSTEXPR auto operator[](size_t index) -> Char& { return data_[index]; } -+ FMT_CONSTEXPR auto operator[](size_t index) const -> const Char& { -+ return data_[index]; -+ } - }; --struct wformat_args : basic_format_args<wformat_context> { -- using basic_format_args::basic_format_args; -+FMT_END_DETAIL_NAMESPACE -+ -+// Format specifiers for built-in and string types. -+template <typename Char> struct basic_format_specs { -+ int width; -+ int precision; -+ char type; -+ align_t align : 4; -+ sign_t sign : 3; -+ bool alt : 1; // Alternate form ('#'). -+ bool localized : 1; -+ detail::fill_t<Char> fill; -+ -+ constexpr basic_format_specs() -+ : width(0), -+ precision(-1), -+ type(0), -+ align(align::none), -+ sign(sign::none), -+ alt(false), -+ localized(false) {} - }; -+ -+using format_specs = basic_format_specs<char>; -+ -+FMT_BEGIN_DETAIL_NAMESPACE -+ -+enum class arg_id_kind { none, index, name }; -+ -+// An argument reference. -+template <typename Char> struct arg_ref { -+ FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {} -+ -+ FMT_CONSTEXPR explicit arg_ref(int index) -+ : kind(arg_id_kind::index), val(index) {} -+ FMT_CONSTEXPR explicit arg_ref(basic_string_view<Char> name) -+ : kind(arg_id_kind::name), val(name) {} -+ -+ FMT_CONSTEXPR auto operator=(int idx) -> arg_ref& { -+ kind = arg_id_kind::index; -+ val.index = idx; -+ return *this; -+ } -+ -+ arg_id_kind kind; -+ union value { -+ FMT_CONSTEXPR value(int id = 0) : index{id} {} -+ FMT_CONSTEXPR value(basic_string_view<Char> n) : name(n) {} -+ -+ int index; -+ basic_string_view<Char> name; -+ } val; -+}; -+ -+// Format specifiers with width and precision resolved at formatting rather -+// than parsing time to allow re-using the same parsed specifiers with -+// different sets of arguments (precompilation of format strings). -+template <typename Char> -+struct dynamic_format_specs : basic_format_specs<Char> { -+ arg_ref<Char> width_ref; -+ arg_ref<Char> precision_ref; -+}; -+ -+struct auto_id {}; -+ -+// A format specifier handler that sets fields in basic_format_specs. -+template <typename Char> class specs_setter { -+ protected: -+ basic_format_specs<Char>& specs_; -+ -+ public: -+ explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char>& specs) -+ : specs_(specs) {} -+ -+ FMT_CONSTEXPR specs_setter(const specs_setter& other) -+ : specs_(other.specs_) {} -+ -+ FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; } -+ FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) { -+ specs_.fill = fill; -+ } -+ FMT_CONSTEXPR void on_sign(sign_t s) { specs_.sign = s; } -+ FMT_CONSTEXPR void on_hash() { specs_.alt = true; } -+ FMT_CONSTEXPR void on_localized() { specs_.localized = true; } -+ -+ FMT_CONSTEXPR void on_zero() { -+ if (specs_.align == align::none) specs_.align = align::numeric; -+ specs_.fill[0] = Char('0'); -+ } -+ -+ FMT_CONSTEXPR void on_width(int width) { specs_.width = width; } -+ FMT_CONSTEXPR void on_precision(int precision) { -+ specs_.precision = precision; -+ } -+ FMT_CONSTEXPR void end_precision() {} -+ -+ FMT_CONSTEXPR void on_type(Char type) { -+ specs_.type = static_cast<char>(type); -+ } -+}; -+ -+// Format spec handler that saves references to arguments representing dynamic -+// width and precision to be resolved at formatting time. -+template <typename ParseContext> -+class dynamic_specs_handler -+ : public specs_setter<typename ParseContext::char_type> { -+ public: -+ using char_type = typename ParseContext::char_type; -+ -+ FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs<char_type>& specs, -+ ParseContext& ctx) -+ : specs_setter<char_type>(specs), specs_(specs), context_(ctx) {} -+ -+ FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler& other) -+ : specs_setter<char_type>(other), -+ specs_(other.specs_), -+ context_(other.context_) {} -+ -+ template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { -+ specs_.width_ref = make_arg_ref(arg_id); -+ } -+ -+ template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { -+ specs_.precision_ref = make_arg_ref(arg_id); -+ } -+ -+ FMT_CONSTEXPR void on_error(const char* message) { -+ context_.on_error(message); -+ } -+ -+ private: -+ dynamic_format_specs<char_type>& specs_; -+ ParseContext& context_; -+ -+ using arg_ref_type = arg_ref<char_type>; -+ -+ FMT_CONSTEXPR auto make_arg_ref(int arg_id) -> arg_ref_type { -+ context_.check_arg_id(arg_id); -+ return arg_ref_type(arg_id); -+ } -+ -+ FMT_CONSTEXPR auto make_arg_ref(auto_id) -> arg_ref_type { -+ return arg_ref_type(context_.next_arg_id()); -+ } -+ -+ FMT_CONSTEXPR auto make_arg_ref(basic_string_view<char_type> arg_id) -+ -> arg_ref_type { -+ context_.check_arg_id(arg_id); -+ basic_string_view<char_type> format_str( -+ context_.begin(), to_unsigned(context_.end() - context_.begin())); -+ return arg_ref_type(arg_id); -+ } -+}; -+ -+template <typename Char> constexpr bool is_ascii_letter(Char c) { -+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); -+} -+ -+// Converts a character to ASCII. Returns a number > 127 on conversion failure. -+template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)> -+constexpr auto to_ascii(Char value) -> Char { -+ return value; -+} -+template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)> -+constexpr auto to_ascii(Char value) -> -+ typename std::underlying_type<Char>::type { -+ return value; -+} -+ -+template <typename Char> -+FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int { -+ if (const_check(sizeof(Char) != 1)) return 1; -+ constexpr char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0}; -+ int len = lengths[static_cast<unsigned char>(*begin) >> 3]; -+ -+ // Compute the pointer to the next character early so that the next -+ // iteration can start working on the next character. Neither Clang -+ // nor GCC figure out this reordering on their own. -+ return len + !len; -+} -+ -+// Return the result via the out param to workaround gcc bug 77539. -+template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*> -+FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool { -+ for (out = first; out != last; ++out) { -+ if (*out == value) return true; -+ } -+ return false; -+} -+ -+template <> -+inline auto find<false, char>(const char* first, const char* last, char value, -+ const char*& out) -> bool { -+ out = static_cast<const char*>( -+ std::memchr(first, value, to_unsigned(last - first))); -+ return out != nullptr; -+} -+ -+// Parses the range [begin, end) as an unsigned integer. This function assumes -+// that the range is non-empty and the first character is a digit. -+template <typename Char> -+FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end, -+ int error_value) noexcept -> int { -+ FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', ""); -+ unsigned value = 0, prev = 0; -+ auto p = begin; -+ do { -+ prev = value; -+ value = value * 10 + unsigned(*p - '0'); -+ ++p; -+ } while (p != end && '0' <= *p && *p <= '9'); -+ auto num_digits = p - begin; -+ begin = p; -+ if (num_digits <= std::numeric_limits<int>::digits10) -+ return static_cast<int>(value); -+ // Check for overflow. -+ const unsigned max = to_unsigned((std::numeric_limits<int>::max)()); -+ return num_digits == std::numeric_limits<int>::digits10 + 1 && -+ prev * 10ull + unsigned(p[-1] - '0') <= max -+ ? static_cast<int>(value) -+ : error_value; -+} -+ -+// Parses fill and alignment. -+template <typename Char, typename Handler> -+FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end, -+ Handler&& handler) -> const Char* { -+ FMT_ASSERT(begin != end, ""); -+ auto align = align::none; -+ auto p = begin + code_point_length(begin); -+ if (p >= end) p = begin; -+ for (;;) { -+ switch (to_ascii(*p)) { -+ case '<': -+ align = align::left; -+ break; -+ case '>': -+ align = align::right; -+ break; -+ case '^': -+ align = align::center; -+ break; -+ default: -+ break; -+ } -+ if (align != align::none) { -+ if (p != begin) { -+ auto c = *begin; -+ if (c == '{') -+ return handler.on_error("invalid fill character '{'"), begin; -+ handler.on_fill(basic_string_view<Char>(begin, to_unsigned(p - begin))); -+ begin = p + 1; -+ } else -+ ++begin; -+ handler.on_align(align); -+ break; -+ } else if (p == begin) { -+ break; -+ } -+ p = begin; -+ } -+ return begin; -+} -+ -+template <typename Char> FMT_CONSTEXPR bool is_name_start(Char c) { -+ return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; -+} -+ -+template <typename Char, typename IDHandler> -+FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end, -+ IDHandler&& handler) -> const Char* { -+ FMT_ASSERT(begin != end, ""); -+ Char c = *begin; -+ if (c >= '0' && c <= '9') { -+ int index = 0; -+ if (c != '0') -+ index = -+ parse_nonnegative_int(begin, end, (std::numeric_limits<int>::max)()); -+ else -+ ++begin; -+ if (begin == end || (*begin != '}' && *begin != ':')) -+ handler.on_error("invalid format string"); -+ else -+ handler(index); -+ return begin; -+ } -+ if (!is_name_start(c)) { -+ handler.on_error("invalid format string"); -+ return begin; -+ } -+ auto it = begin; -+ do { -+ ++it; -+ } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9'))); -+ handler(basic_string_view<Char>(begin, to_unsigned(it - begin))); -+ return it; -+} -+ -+template <typename Char, typename IDHandler> -+FMT_CONSTEXPR FMT_INLINE auto parse_arg_id(const Char* begin, const Char* end, -+ IDHandler&& handler) -> const Char* { -+ Char c = *begin; -+ if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler); -+ handler(); -+ return begin; -+} -+ -+template <typename Char, typename Handler> -+FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end, -+ Handler&& handler) -> const Char* { -+ using detail::auto_id; -+ struct width_adapter { -+ Handler& handler; -+ -+ FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); } -+ FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); } -+ FMT_CONSTEXPR void operator()(basic_string_view<Char> id) { -+ handler.on_dynamic_width(id); -+ } -+ FMT_CONSTEXPR void on_error(const char* message) { -+ if (message) handler.on_error(message); -+ } -+ }; -+ -+ FMT_ASSERT(begin != end, ""); -+ if ('0' <= *begin && *begin <= '9') { -+ int width = parse_nonnegative_int(begin, end, -1); -+ if (width != -1) -+ handler.on_width(width); -+ else -+ handler.on_error("number is too big"); -+ } else if (*begin == '{') { -+ ++begin; -+ if (begin != end) begin = parse_arg_id(begin, end, width_adapter{handler}); -+ if (begin == end || *begin != '}') -+ return handler.on_error("invalid format string"), begin; -+ ++begin; -+ } -+ return begin; -+} -+ -+template <typename Char, typename Handler> -+FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end, -+ Handler&& handler) -> const Char* { -+ using detail::auto_id; -+ struct precision_adapter { -+ Handler& handler; -+ -+ FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); } -+ FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); } -+ FMT_CONSTEXPR void operator()(basic_string_view<Char> id) { -+ handler.on_dynamic_precision(id); -+ } -+ FMT_CONSTEXPR void on_error(const char* message) { -+ if (message) handler.on_error(message); -+ } -+ }; -+ -+ ++begin; -+ auto c = begin != end ? *begin : Char(); -+ if ('0' <= c && c <= '9') { -+ auto precision = parse_nonnegative_int(begin, end, -1); -+ if (precision != -1) -+ handler.on_precision(precision); -+ else -+ handler.on_error("number is too big"); -+ } else if (c == '{') { -+ ++begin; -+ if (begin != end) -+ begin = parse_arg_id(begin, end, precision_adapter{handler}); -+ if (begin == end || *begin++ != '}') -+ return handler.on_error("invalid format string"), begin; -+ } else { -+ return handler.on_error("missing precision specifier"), begin; -+ } -+ handler.end_precision(); -+ return begin; -+} -+ -+// Parses standard format specifiers and sends notifications about parsed -+// components to handler. -+template <typename Char, typename SpecHandler> -+FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin, -+ const Char* end, -+ SpecHandler&& handler) -+ -> const Char* { -+ if (begin + 1 < end && begin[1] == '}' && is_ascii_letter(*begin) && -+ *begin != 'L') { -+ handler.on_type(*begin++); -+ return begin; -+ } -+ -+ if (begin == end) return begin; -+ -+ begin = parse_align(begin, end, handler); -+ if (begin == end) return begin; -+ -+ // Parse sign. -+ switch (to_ascii(*begin)) { -+ case '+': -+ handler.on_sign(sign::plus); -+ ++begin; -+ break; -+ case '-': -+ handler.on_sign(sign::minus); -+ ++begin; -+ break; -+ case ' ': -+ handler.on_sign(sign::space); -+ ++begin; -+ break; -+ default: -+ break; -+ } -+ if (begin == end) return begin; -+ -+ if (*begin == '#') { -+ handler.on_hash(); -+ if (++begin == end) return begin; -+ } -+ -+ // Parse zero flag. -+ if (*begin == '0') { -+ handler.on_zero(); -+ if (++begin == end) return begin; -+ } -+ -+ begin = parse_width(begin, end, handler); -+ if (begin == end) return begin; -+ -+ // Parse precision. -+ if (*begin == '.') { -+ begin = parse_precision(begin, end, handler); -+ if (begin == end) return begin; -+ } -+ -+ if (*begin == 'L') { -+ handler.on_localized(); -+ ++begin; -+ } -+ -+ // Parse type. -+ if (begin != end && *begin != '}') handler.on_type(*begin++); -+ return begin; -+} -+ -+template <typename Char, typename Handler> -+FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end, -+ Handler&& handler) -> const Char* { -+ struct id_adapter { -+ Handler& handler; -+ int arg_id; -+ -+ FMT_CONSTEXPR void operator()() { arg_id = handler.on_arg_id(); } -+ FMT_CONSTEXPR void operator()(int id) { arg_id = handler.on_arg_id(id); } -+ FMT_CONSTEXPR void operator()(basic_string_view<Char> id) { -+ arg_id = handler.on_arg_id(id); -+ } -+ FMT_CONSTEXPR void on_error(const char* message) { -+ if (message) handler.on_error(message); -+ } -+ }; -+ -+ ++begin; -+ if (begin == end) return handler.on_error("invalid format string"), end; -+ if (*begin == '}') { -+ handler.on_replacement_field(handler.on_arg_id(), begin); -+ } else if (*begin == '{') { -+ handler.on_text(begin, begin + 1); -+ } else { -+ auto adapter = id_adapter{handler, 0}; -+ begin = parse_arg_id(begin, end, adapter); -+ Char c = begin != end ? *begin : Char(); -+ if (c == '}') { -+ handler.on_replacement_field(adapter.arg_id, begin); -+ } else if (c == ':') { -+ begin = handler.on_format_specs(adapter.arg_id, begin + 1, end); -+ if (begin == end || *begin != '}') -+ return handler.on_error("unknown format specifier"), end; -+ } else { -+ return handler.on_error("missing '}' in format string"), end; -+ } -+ } -+ return begin + 1; -+} -+ -+template <bool IS_CONSTEXPR, typename Char, typename Handler> -+FMT_CONSTEXPR FMT_INLINE void parse_format_string( -+ basic_string_view<Char> format_str, Handler&& handler) { -+ // this is most likely a name-lookup defect in msvc's modules implementation -+ using detail::find; -+ -+ auto begin = format_str.data(); -+ auto end = begin + format_str.size(); -+ if (end - begin < 32) { -+ // Use a simple loop instead of memchr for small strings. -+ const Char* p = begin; -+ while (p != end) { -+ auto c = *p++; -+ if (c == '{') { -+ handler.on_text(begin, p - 1); -+ begin = p = parse_replacement_field(p - 1, end, handler); -+ } else if (c == '}') { -+ if (p == end || *p != '}') -+ return handler.on_error("unmatched '}' in format string"); -+ handler.on_text(begin, p); -+ begin = ++p; -+ } -+ } -+ handler.on_text(begin, end); -+ return; -+ } -+ struct writer { -+ FMT_CONSTEXPR void operator()(const Char* pbegin, const Char* pend) { -+ if (pbegin == pend) return; -+ for (;;) { -+ const Char* p = nullptr; -+ if (!find<IS_CONSTEXPR>(pbegin, pend, '}', p)) -+ return handler_.on_text(pbegin, pend); -+ ++p; -+ if (p == pend || *p != '}') -+ return handler_.on_error("unmatched '}' in format string"); -+ handler_.on_text(pbegin, p); -+ pbegin = p + 1; -+ } -+ } -+ Handler& handler_; -+ } write{handler}; -+ while (begin != end) { -+ // Doing two passes with memchr (one for '{' and another for '}') is up to -+ // 2.5x faster than the naive one-pass implementation on big format strings. -+ const Char* p = begin; -+ if (*begin != '{' && !find<IS_CONSTEXPR>(begin + 1, end, '{', p)) -+ return write(begin, end); -+ write(begin, p); -+ begin = parse_replacement_field(p, end, handler); -+ } -+} -+ -+template <typename T, typename ParseContext> -+FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx) -+ -> decltype(ctx.begin()) { -+ using char_type = typename ParseContext::char_type; -+ using context = buffer_context<char_type>; -+ using mapped_type = conditional_t< -+ mapped_type_constant<T, context>::value != type::custom_type, -+ decltype(arg_mapper<context>().map(std::declval<const T&>())), T>; -+ auto f = conditional_t<has_formatter<mapped_type, context>::value, -+ formatter<mapped_type, char_type>, -+ fallback_formatter<T, char_type>>(); -+ return f.parse(ctx); -+} -+ -+// A parse context with extra argument id checks. It is only used at compile -+// time because adding checks at runtime would introduce substantial overhead -+// and would be redundant since argument ids are checked when arguments are -+// retrieved anyway. -+template <typename Char, typename ErrorHandler = error_handler> -+class compile_parse_context -+ : public basic_format_parse_context<Char, ErrorHandler> { -+ private: -+ int num_args_; -+ using base = basic_format_parse_context<Char, ErrorHandler>; -+ -+ public: -+ explicit FMT_CONSTEXPR compile_parse_context( -+ basic_string_view<Char> format_str, -+ int num_args = (std::numeric_limits<int>::max)(), ErrorHandler eh = {}) -+ : base(format_str, eh), num_args_(num_args) {} -+ -+ FMT_CONSTEXPR auto next_arg_id() -> int { -+ int id = base::next_arg_id(); -+ if (id >= num_args_) this->on_error("argument not found"); -+ return id; -+ } -+ -+ FMT_CONSTEXPR void check_arg_id(int id) { -+ base::check_arg_id(id); -+ if (id >= num_args_) this->on_error("argument not found"); -+ } -+ using base::check_arg_id; -+}; -+ -+template <typename ErrorHandler> -+FMT_CONSTEXPR void check_int_type_spec(char spec, ErrorHandler&& eh) { -+ switch (spec) { -+ case 0: -+ case 'd': -+ case 'x': -+ case 'X': -+ case 'b': -+ case 'B': -+ case 'o': -+ case 'c': -+ break; -+ default: -+ eh.on_error("invalid type specifier"); -+ break; -+ } -+} -+ -+// Checks char specs and returns true if the type spec is char (and not int). -+template <typename Char, typename ErrorHandler = error_handler> -+FMT_CONSTEXPR auto check_char_specs(const basic_format_specs<Char>& specs, -+ ErrorHandler&& eh = {}) -> bool { -+ if (specs.type && specs.type != 'c') { -+ check_int_type_spec(specs.type, eh); -+ return false; -+ } -+ if (specs.align == align::numeric || specs.sign != sign::none || specs.alt) -+ eh.on_error("invalid format specifier for char"); -+ return true; -+} -+ -+// A floating-point presentation format. -+enum class float_format : unsigned char { -+ general, // General: exponent notation or fixed point based on magnitude. -+ exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3. -+ fixed, // Fixed point with the default precision of 6, e.g. 0.0012. -+ hex -+}; -+ -+struct float_specs { -+ int precision; -+ float_format format : 8; -+ sign_t sign : 8; -+ bool upper : 1; -+ bool locale : 1; -+ bool binary32 : 1; -+ bool use_grisu : 1; -+ bool showpoint : 1; -+}; -+ -+template <typename ErrorHandler = error_handler, typename Char> -+FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs<Char>& specs, -+ ErrorHandler&& eh = {}) -+ -> float_specs { -+ auto result = float_specs(); -+ result.showpoint = specs.alt; -+ result.locale = specs.localized; -+ switch (specs.type) { -+ case 0: -+ result.format = float_format::general; -+ break; -+ case 'G': -+ result.upper = true; -+ FMT_FALLTHROUGH; -+ case 'g': -+ result.format = float_format::general; -+ break; -+ case 'E': -+ result.upper = true; -+ FMT_FALLTHROUGH; -+ case 'e': -+ result.format = float_format::exp; -+ result.showpoint |= specs.precision != 0; -+ break; -+ case 'F': -+ result.upper = true; -+ FMT_FALLTHROUGH; -+ case 'f': -+ result.format = float_format::fixed; -+ result.showpoint |= specs.precision != 0; -+ break; -+ case 'A': -+ result.upper = true; -+ FMT_FALLTHROUGH; -+ case 'a': -+ result.format = float_format::hex; -+ break; -+ default: -+ eh.on_error("invalid type specifier"); -+ break; -+ } -+ return result; -+} -+ -+template <typename Char, typename ErrorHandler = error_handler> -+FMT_CONSTEXPR auto check_cstring_type_spec(Char spec, ErrorHandler&& eh = {}) -+ -> bool { -+ if (spec == 0 || spec == 's') return true; -+ if (spec != 'p') eh.on_error("invalid type specifier"); -+ return false; -+} -+ -+template <typename Char, typename ErrorHandler> -+FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler&& eh) { -+ if (spec != 0 && spec != 's') eh.on_error("invalid type specifier"); -+} -+ -+template <typename Char, typename ErrorHandler> -+FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) { -+ if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier"); -+} -+ -+// A parse_format_specs handler that checks if specifiers are consistent with -+// the argument type. -+template <typename Handler> class specs_checker : public Handler { -+ private: -+ detail::type arg_type_; -+ -+ FMT_CONSTEXPR void require_numeric_argument() { -+ if (!is_arithmetic_type(arg_type_)) -+ this->on_error("format specifier requires numeric argument"); -+ } -+ -+ public: -+ FMT_CONSTEXPR specs_checker(const Handler& handler, detail::type arg_type) -+ : Handler(handler), arg_type_(arg_type) {} -+ -+ FMT_CONSTEXPR void on_align(align_t align) { -+ if (align == align::numeric) require_numeric_argument(); -+ Handler::on_align(align); -+ } -+ -+ FMT_CONSTEXPR void on_sign(sign_t s) { -+ require_numeric_argument(); -+ if (is_integral_type(arg_type_) && arg_type_ != type::int_type && -+ arg_type_ != type::long_long_type && arg_type_ != type::char_type) { -+ this->on_error("format specifier requires signed argument"); -+ } -+ Handler::on_sign(s); -+ } -+ -+ FMT_CONSTEXPR void on_hash() { -+ require_numeric_argument(); -+ Handler::on_hash(); -+ } -+ -+ FMT_CONSTEXPR void on_localized() { -+ require_numeric_argument(); -+ Handler::on_localized(); -+ } -+ -+ FMT_CONSTEXPR void on_zero() { -+ require_numeric_argument(); -+ Handler::on_zero(); -+ } -+ -+ FMT_CONSTEXPR void end_precision() { -+ if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type) -+ this->on_error("precision not allowed for this argument type"); -+ } -+}; -+ -+constexpr int invalid_arg_index = -1; -+ -+#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -+template <int N, typename T, typename... Args, typename Char> -+constexpr auto get_arg_index_by_name(basic_string_view<Char> name) -> int { -+ if constexpr (detail::is_statically_named_arg<T>()) { -+ if (name == T::name) return N; -+ } -+ if constexpr (sizeof...(Args) > 0) -+ return get_arg_index_by_name<N + 1, Args...>(name); -+ (void)name; // Workaround an MSVC bug about "unused" parameter. -+ return invalid_arg_index; -+} - #endif - --namespace detail { -+template <typename... Args, typename Char> -+FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view<Char> name) -> int { -+#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -+ if constexpr (sizeof...(Args) > 0) -+ return get_arg_index_by_name<0, Args...>(name); -+#endif -+ (void)name; -+ return invalid_arg_index; -+} -+ -+template <typename Char, typename ErrorHandler, typename... Args> -+class format_string_checker { -+ private: -+ using parse_context_type = compile_parse_context<Char, ErrorHandler>; -+ enum { num_args = sizeof...(Args) }; -+ -+ // Format specifier parsing function. -+ using parse_func = const Char* (*)(parse_context_type&); -+ -+ parse_context_type context_; -+ parse_func parse_funcs_[num_args > 0 ? num_args : 1]; -+ -+ public: -+ explicit FMT_CONSTEXPR format_string_checker( -+ basic_string_view<Char> format_str, ErrorHandler eh) -+ : context_(format_str, num_args, eh), -+ parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {} -+ -+ FMT_CONSTEXPR void on_text(const Char*, const Char*) {} - --template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)> --std::basic_string<Char> vformat( -- basic_string_view<Char> format_str, -- basic_format_args<buffer_context<type_identity_t<Char>>> args); -+ FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); } -+ FMT_CONSTEXPR auto on_arg_id(int id) -> int { -+ return context_.check_arg_id(id), id; -+ } -+ FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int { -+#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -+ auto index = get_arg_index_by_name<Args...>(id); -+ if (index == invalid_arg_index) on_error("named argument is not found"); -+ return context_.check_arg_id(index), index; -+#else -+ (void)id; -+ on_error("compile-time checks for named arguments require C++20 support"); -+ return 0; -+#endif -+ } -+ -+ FMT_CONSTEXPR void on_replacement_field(int, const Char*) {} -+ -+ FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char*) -+ -> const Char* { -+ context_.advance_to(context_.begin() + (begin - &*context_.begin())); -+ // id >= 0 check is a workaround for gcc 10 bug (#2065). -+ return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin; -+ } -+ -+ FMT_CONSTEXPR void on_error(const char* message) { -+ context_.on_error(message); -+ } -+}; - --FMT_API std::string vformat(string_view format_str, format_args args); -+template <typename... Args, typename S, -+ enable_if_t<(is_compile_string<S>::value), int>> -+void check_format_string(S format_str) { -+ FMT_CONSTEXPR auto s = to_string_view(format_str); -+ using checker = format_string_checker<typename S::char_type, error_handler, -+ remove_cvref_t<Args>...>; -+ FMT_CONSTEXPR bool invalid_format = -+ (parse_format_string<true>(s, checker(s, {})), true); -+ (void)invalid_format; -+} - - template <typename Char> - void vformat_to( -- buffer<Char>& buf, basic_string_view<Char> format_str, -+ buffer<Char>& buf, basic_string_view<Char> fmt, - basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args, - detail::locale_ref loc = {}); - --template <typename Char, typename Args, -- FMT_ENABLE_IF(!std::is_same<Char, char>::value)> --inline void vprint_mojibake(std::FILE*, basic_string_view<Char>, const Args&) {} -- - FMT_API void vprint_mojibake(std::FILE*, string_view, format_args); - #ifndef _WIN32 - inline void vprint_mojibake(std::FILE*, string_view, format_args) {} - #endif --} // namespace detail -+FMT_END_DETAIL_NAMESPACE -+ -+// A formatter specialization for the core types corresponding to detail::type -+// constants. -+template <typename T, typename Char> -+struct formatter<T, Char, -+ enable_if_t<detail::type_constant<T, Char>::value != -+ detail::type::custom_type>> { -+ private: -+ detail::dynamic_format_specs<Char> specs_; -+ -+ public: -+ // Parses format specifiers stopping either at the end of the range or at the -+ // terminating '}'. -+ template <typename ParseContext> -+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { -+ auto begin = ctx.begin(), end = ctx.end(); -+ if (begin == end) return begin; -+ using handler_type = detail::dynamic_specs_handler<ParseContext>; -+ auto type = detail::type_constant<T, Char>::value; -+ auto checker = -+ detail::specs_checker<handler_type>(handler_type(specs_, ctx), type); -+ auto it = detail::parse_format_specs(begin, end, checker); -+ auto eh = ctx.error_handler(); -+ switch (type) { -+ case detail::type::none_type: -+ FMT_ASSERT(false, "invalid argument type"); -+ break; -+ case detail::type::bool_type: -+ if (!specs_.type || specs_.type == 's') break; -+ FMT_FALLTHROUGH; -+ case detail::type::int_type: -+ case detail::type::uint_type: -+ case detail::type::long_long_type: -+ case detail::type::ulong_long_type: -+ case detail::type::int128_type: -+ case detail::type::uint128_type: -+ detail::check_int_type_spec(specs_.type, eh); -+ break; -+ case detail::type::char_type: -+ detail::check_char_specs(specs_, eh); -+ break; -+ case detail::type::float_type: -+ if (detail::const_check(FMT_USE_FLOAT)) -+ detail::parse_float_type_spec(specs_, eh); -+ else -+ FMT_ASSERT(false, "float support disabled"); -+ break; -+ case detail::type::double_type: -+ if (detail::const_check(FMT_USE_DOUBLE)) -+ detail::parse_float_type_spec(specs_, eh); -+ else -+ FMT_ASSERT(false, "double support disabled"); -+ break; -+ case detail::type::long_double_type: -+ if (detail::const_check(FMT_USE_LONG_DOUBLE)) -+ detail::parse_float_type_spec(specs_, eh); -+ else -+ FMT_ASSERT(false, "long double support disabled"); -+ break; -+ case detail::type::cstring_type: -+ detail::check_cstring_type_spec(specs_.type, eh); -+ break; -+ case detail::type::string_type: -+ detail::check_string_type_spec(specs_.type, eh); -+ break; -+ case detail::type::pointer_type: -+ detail::check_pointer_type_spec(specs_.type, eh); -+ break; -+ case detail::type::custom_type: -+ // Custom format specifiers are checked in parse functions of -+ // formatter specializations. -+ break; -+ } -+ return it; -+ } -+ -+ template <typename FormatContext> -+ FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const -+ -> decltype(ctx.out()); -+}; -+ -+template <typename Char> struct basic_runtime { basic_string_view<Char> str; }; -+ -+template <typename Char, typename... Args> class basic_format_string { -+ private: -+ basic_string_view<Char> str_; -+ -+ public: -+ template <typename S, -+ FMT_ENABLE_IF( -+ std::is_convertible<const S&, basic_string_view<Char>>::value)> -+ FMT_CONSTEVAL basic_format_string(const S& s) : str_(s) { -+ static_assert( -+ detail::count< -+ (std::is_base_of<detail::view, remove_reference_t<Args>>::value && -+ std::is_reference<Args>::value)...>() == 0, -+ "passing views as lvalues is disallowed"); -+#ifdef FMT_HAS_CONSTEVAL -+ if constexpr (detail::count_named_args<Args...>() == 0) { -+ using checker = detail::format_string_checker<Char, detail::error_handler, -+ remove_cvref_t<Args>...>; -+ detail::parse_format_string<true>(str_, checker(s, {})); -+ } -+#else -+ detail::check_format_string<Args...>(s); -+#endif -+ } -+ basic_format_string(basic_runtime<Char> r) : str_(r.str) {} -+ -+ FMT_INLINE operator basic_string_view<Char>() const { return str_; } -+}; -+ -+#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 -+// Workaround broken conversion on older gcc. -+template <typename... Args> using format_string = string_view; -+template <typename S> auto runtime(const S& s) -> basic_string_view<char_t<S>> { -+ return s; -+} -+#else -+template <typename... Args> -+using format_string = basic_format_string<char, type_identity_t<Args>...>; -+// Creates a runtime format string. -+template <typename S> auto runtime(const S& s) -> basic_runtime<char_t<S>> { -+ return {{s}}; -+} -+#endif -+ -+FMT_API auto vformat(string_view fmt, format_args args) -> std::string; -+ -+/** -+ \rst -+ Formats ``args`` according to specifications in ``fmt`` and returns the result -+ as a string. -+ -+ **Example**:: -+ -+ #include <fmt/core.h> -+ std::string message = fmt::format("The answer is {}", 42); -+ \endrst -+*/ -+template <typename... T> -+FMT_INLINE auto format(format_string<T...> fmt, T&&... args) -> std::string { -+ return vformat(fmt, fmt::make_format_args(args...)); -+} - - /** Formats a string and writes the output to ``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>, -- bool enable = detail::is_output_iterator<OutputIt, Char>::value> --auto vformat_to(OutputIt out, const S& format_str, -- basic_format_args<buffer_context<type_identity_t<Char>>> args) -- -> typename std::enable_if<enable, OutputIt>::type { -- decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out)); -- detail::vformat_to(buf, to_string_view(format_str), args); -+template <typename OutputIt, -+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)> -+auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt { -+ using detail::get_buffer; -+ auto&& buf = get_buffer<char>(out); -+ detail::vformat_to(buf, string_view(fmt), args); - return detail::get_iterator(buf); - } - - /** - \rst -- Formats arguments, writes the result to the output iterator ``out`` and returns -- the iterator past the end of the output range. -+ Formats ``args`` according to specifications in ``fmt``, writes the result to -+ the output iterator ``out`` and returns the iterator past the end of the output -+ range. - - **Example**:: - -- std::vector<char> out; -+ auto out = std::vector<char>(); - fmt::format_to(std::back_inserter(out), "{}", 42); - \endrst - */ --// We cannot use FMT_ENABLE_IF because of a bug in gcc 8.3. --template <typename OutputIt, typename S, typename... Args, -- bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value> --inline auto format_to(OutputIt out, const S& format_str, Args&&... args) -> -- typename std::enable_if<enable, OutputIt>::type { -- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); -- return vformat_to(out, to_string_view(format_str), vargs); -+template <typename OutputIt, typename... T, -+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)> -+FMT_INLINE auto format_to(OutputIt out, format_string<T...> fmt, T&&... args) -+ -> OutputIt { -+ return vformat_to(out, fmt, fmt::make_format_args(args...)); - } - - template <typename OutputIt> struct format_to_n_result { -@@ -2012,111 +2926,81 @@ template <typename OutputIt> struct format_to_n_result { - size_t size; - }; - --template <typename OutputIt, typename Char, typename... Args, -- FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)> --inline format_to_n_result<OutputIt> vformat_to_n( -- OutputIt out, size_t n, basic_string_view<Char> format_str, -- basic_format_args<buffer_context<type_identity_t<Char>>> args) { -- detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out, -- n); -- detail::vformat_to(buf, format_str, args); -+template <typename OutputIt, typename... T, -+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)> -+auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args) -+ -> format_to_n_result<OutputIt> { -+ using buffer = -+ detail::iterator_buffer<OutputIt, char, detail::fixed_buffer_traits>; -+ auto buf = buffer(out, n); -+ detail::vformat_to(buf, fmt, args); - return {buf.out(), buf.count()}; - } - - /** -- \rst -- Formats arguments, writes up to ``n`` characters of the result to the output -- iterator ``out`` and returns the total output size and the iterator past the -- end of the output range. -- \endrst -+ \rst -+ Formats ``args`` according to specifications in ``fmt``, writes up to ``n`` -+ characters of the result to the output iterator ``out`` and returns the total -+ (not truncated) output size and the iterator past the end of the output range. -+ \endrst - */ --template <typename OutputIt, typename S, typename... Args, -- bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value> --inline auto format_to_n(OutputIt out, size_t n, const S& format_str, -- const Args&... args) -> -- typename std::enable_if<enable, format_to_n_result<OutputIt>>::type { -- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); -- return vformat_to_n(out, n, to_string_view(format_str), vargs); -+template <typename OutputIt, typename... T, -+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)> -+FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string<T...> fmt, -+ const T&... args) -> format_to_n_result<OutputIt> { -+ return vformat_to_n(out, n, fmt, fmt::make_format_args(args...)); - } - --/** -- Returns the number of characters in the output of -- ``format(format_str, args...)``. -- */ --template <typename... Args> --inline size_t formatted_size(string_view format_str, Args&&... args) { -- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); -- detail::counting_buffer<> buf; -- detail::vformat_to(buf, format_str, vargs); -+/** Returns the number of chars in the output of ``format(fmt, args...)``. */ -+template <typename... T> -+FMT_INLINE auto formatted_size(format_string<T...> fmt, T&&... args) -> size_t { -+ auto buf = detail::counting_buffer<>(); -+ detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...)); - return buf.count(); - } - --template <typename S, typename Char = char_t<S>> --FMT_INLINE std::basic_string<Char> vformat( -- const S& format_str, -- basic_format_args<buffer_context<type_identity_t<Char>>> args) { -- return detail::vformat(to_string_view(format_str), args); --} -+FMT_API void vprint(string_view fmt, format_args args); -+FMT_API void vprint(std::FILE* f, string_view fmt, format_args args); - - /** - \rst -- Formats arguments and returns the result as a string. -+ Formats ``args`` according to specifications in ``fmt`` and writes the output -+ to ``stdout``. - - **Example**:: - -- #include <fmt/core.h> -- std::string message = fmt::format("The answer is {}", 42); -+ fmt::print("Elapsed time: {0:.2f} seconds", 1.23); - \endrst --*/ --// 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>> --FMT_INLINE std::basic_string<Char> format(const S& format_str, Args&&... args) { -- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); -- return detail::vformat(to_string_view(format_str), vargs); -+ */ -+template <typename... T> -+FMT_INLINE void print(format_string<T...> fmt, T&&... args) { -+ const auto& vargs = fmt::make_format_args(args...); -+ return detail::is_utf8() ? vprint(fmt, vargs) -+ : detail::vprint_mojibake(stdout, fmt, vargs); - } - --FMT_API void vprint(string_view, format_args); --FMT_API void vprint(std::FILE*, string_view, format_args); -- - /** - \rst -- Formats ``args`` according to specifications in ``format_str`` and writes the -- output to the file ``f``. Strings are assumed to be Unicode-encoded unless the -- ``FMT_UNICODE`` macro is set to 0. -+ Formats ``args`` according to specifications in ``fmt`` and writes the -+ output to the file ``f``. - - **Example**:: - - fmt::print(stderr, "Don't {}!", "panic"); - \endrst - */ --template <typename S, typename... Args, typename Char = char_t<S>> --inline void print(std::FILE* f, const S& format_str, Args&&... args) { -- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); -- return detail::is_unicode<Char>() -- ? vprint(f, to_string_view(format_str), vargs) -- : detail::vprint_mojibake(f, to_string_view(format_str), vargs); -+template <typename... T> -+FMT_INLINE void print(std::FILE* f, format_string<T...> fmt, T&&... args) { -+ const auto& vargs = fmt::make_format_args(args...); -+ return detail::is_utf8() ? vprint(f, fmt, vargs) -+ : detail::vprint_mojibake(f, fmt, vargs); - } - --/** -- \rst -- Formats ``args`` according to specifications in ``format_str`` and writes -- the output to ``stdout``. Strings are assumed to be Unicode-encoded unless -- the ``FMT_UNICODE`` macro is set to 0. -- -- **Example**:: -- -- fmt::print("Elapsed time: {0:.2f} seconds", 1.23); -- \endrst -- */ --template <typename S, typename... Args, typename Char = char_t<S>> --inline void print(const S& format_str, Args&&... args) { -- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); -- return detail::is_unicode<Char>() -- ? vprint(to_string_view(format_str), vargs) -- : detail::vprint_mojibake(stdout, to_string_view(format_str), -- vargs); --} -+FMT_MODULE_EXPORT_END -+FMT_GCC_PRAGMA("GCC pop_options") - FMT_END_NAMESPACE - -+#ifdef FMT_HEADER_ONLY -+# include "format.h" -+#endif - #endif // FMT_CORE_H_ -diff --git a/include/spdlog/fmt/bundled/format-inl.h b/include/spdlog/fmt/bundled/format-inl.h -index 8f2fe735..a802aea5 100644 ---- a/include/spdlog/fmt/bundled/format-inl.h -+++ b/include/spdlog/fmt/bundled/format-inl.h -@@ -8,8 +8,9 @@ - #ifndef FMT_FORMAT_INL_H_ - #define FMT_FORMAT_INL_H_ - --#include <cassert> -+#include <algorithm> - #include <cctype> -+#include <cerrno> // errno - #include <climits> - #include <cmath> - #include <cstdarg> -@@ -27,11 +28,6 @@ - - #include "format.h" - --// Dummy implementations of strerror_r and strerror_s called if corresponding --// system functions are not available. --inline fmt::detail::null<> strerror_r(int, char*, ...) { return {}; } --inline fmt::detail::null<> strerror_s(char*, size_t, ...) { return {}; } -- - FMT_BEGIN_NAMESPACE - namespace detail { - -@@ -57,76 +53,6 @@ inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) { - # define FMT_SNPRINTF fmt_snprintf - #endif // _MSC_VER - --// A portable thread-safe version of strerror. --// Sets buffer to point to a string describing the error code. --// This can be either a pointer to a string stored in buffer, --// or a pointer to some static immutable string. --// Returns one of the following values: --// 0 - success --// ERANGE - buffer is not large enough to store the error message --// other - failure --// Buffer should be at least of size 1. --inline int safe_strerror(int error_code, char*& buffer, -- size_t buffer_size) FMT_NOEXCEPT { -- FMT_ASSERT(buffer != nullptr && buffer_size != 0, "invalid buffer"); -- -- class dispatcher { -- private: -- int error_code_; -- char*& buffer_; -- size_t buffer_size_; -- -- // A noop assignment operator to avoid bogus warnings. -- void operator=(const dispatcher&) {} -- -- // Handle the result of XSI-compliant version of strerror_r. -- int handle(int result) { -- // glibc versions before 2.13 return result in errno. -- return result == -1 ? errno : result; -- } -- -- // Handle the result of GNU-specific version of strerror_r. -- FMT_MAYBE_UNUSED -- int handle(char* message) { -- // If the buffer is full then the message is probably truncated. -- if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) -- return ERANGE; -- buffer_ = message; -- return 0; -- } -- -- // Handle the case when strerror_r is not available. -- FMT_MAYBE_UNUSED -- int handle(detail::null<>) { -- return fallback(strerror_s(buffer_, buffer_size_, error_code_)); -- } -- -- // Fallback to strerror_s when strerror_r is not available. -- FMT_MAYBE_UNUSED -- int fallback(int result) { -- // If the buffer is full then the message is probably truncated. -- return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? ERANGE -- : result; -- } -- --#if !FMT_MSC_VER -- // Fallback to strerror if strerror_r and strerror_s are not available. -- int fallback(detail::null<>) { -- errno = 0; -- buffer_ = strerror(error_code_); -- return errno; -- } --#endif -- -- public: -- dispatcher(int err_code, char*& buf, size_t buf_size) -- : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} -- -- int run() { return handle(strerror_r(error_code_, buffer_, buffer_size_)); } -- }; -- return dispatcher(error_code, buffer, buffer_size).run(); --} -- - FMT_FUNC void format_error_code(detail::buffer<char>& out, int error_code, - string_view message) FMT_NOEXCEPT { - // Report error code making sure that the output fits into -@@ -145,18 +71,18 @@ FMT_FUNC void format_error_code(detail::buffer<char>& out, int error_code, - error_code_size += detail::to_unsigned(detail::count_digits(abs_value)); - auto it = buffer_appender<char>(out); - if (message.size() <= inline_buffer_size - error_code_size) -- format_to(it, "{}{}", message, SEP); -- format_to(it, "{}{}", ERROR_STR, error_code); -- assert(out.size() <= inline_buffer_size); -+ format_to(it, FMT_STRING("{}{}"), message, SEP); -+ format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code); -+ FMT_ASSERT(out.size() <= inline_buffer_size, ""); - } - - FMT_FUNC void report_error(format_func func, int error_code, -- string_view message) FMT_NOEXCEPT { -+ const char* message) FMT_NOEXCEPT { - memory_buffer full_message; - func(full_message, error_code, message); - // Don't use fwrite_fully because the latter may throw. -- (void)std::fwrite(full_message.data(), full_message.size(), 1, stderr); -- std::fputc('\n', stderr); -+ if (std::fwrite(full_message.data(), full_message.size(), 1, stderr) > 0) -+ std::fputc('\n', stderr); - } - - // A wrapper around fwrite that throws on error. -@@ -165,11 +91,8 @@ inline void fwrite_fully(const void* ptr, size_t size, size_t count, - size_t written = std::fwrite(ptr, size, count, stream); - if (written < count) FMT_THROW(system_error(errno, "cannot write to file")); - } --} // namespace detail -- --#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) --namespace detail { - -+#ifndef FMT_STATIC_THOUSANDS_SEPARATOR - template <typename Locale> - locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { - static_assert(std::is_same<Locale, std::locale>::value, ""); -@@ -180,41 +103,36 @@ template <typename Locale> Locale locale_ref::get() const { - return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale(); - } - --template <typename Char> FMT_FUNC std::string grouping_impl(locale_ref loc) { -- return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>()).grouping(); --} --template <typename Char> FMT_FUNC Char thousands_sep_impl(locale_ref loc) { -- return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>()) -- .thousands_sep(); -+template <typename Char> -+FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result<Char> { -+ auto& facet = std::use_facet<std::numpunct<Char>>(loc.get<std::locale>()); -+ auto grouping = facet.grouping(); -+ auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep(); -+ return {std::move(grouping), thousands_sep}; - } - template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref loc) { - return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>()) - .decimal_point(); - } --} // namespace detail - #else - template <typename Char> --FMT_FUNC std::string detail::grouping_impl(locale_ref) { -- return "\03"; -+FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result<Char> { -+ return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR}; - } --template <typename Char> FMT_FUNC Char detail::thousands_sep_impl(locale_ref) { -- return FMT_STATIC_THOUSANDS_SEPARATOR; --} --template <typename Char> FMT_FUNC Char detail::decimal_point_impl(locale_ref) { -+template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) { - return '.'; - } - #endif -+} // namespace detail - -+#if !FMT_MSC_VER - FMT_API FMT_FUNC format_error::~format_error() FMT_NOEXCEPT = default; --FMT_API FMT_FUNC system_error::~system_error() FMT_NOEXCEPT = default; -+#endif - --FMT_FUNC void system_error::init(int err_code, string_view format_str, -- format_args args) { -- error_code_ = err_code; -- memory_buffer buffer; -- format_system_error(buffer, err_code, vformat(format_str, args)); -- std::runtime_error& base = *this; -- base = std::runtime_error(to_string(buffer)); -+FMT_FUNC std::system_error vsystem_error(int error_code, string_view format_str, -+ format_args args) { -+ auto ec = std::error_code(error_code, std::generic_category()); -+ return std::system_error(ec, vformat(format_str, args)); - } - - namespace detail { -@@ -227,854 +145,16 @@ template <> FMT_FUNC int count_digits<4>(detail::fallback_uintptr n) { - return i >= 0 ? i * char_digits + count_digits<4, unsigned>(n.value[i]) : 1; - } - -+#if __cplusplus < 201703L -+template <typename T> constexpr const char basic_data<T>::digits[][2]; -+template <typename T> constexpr const char basic_data<T>::hex_digits[]; -+template <typename T> constexpr const char basic_data<T>::signs[]; -+template <typename T> constexpr const unsigned basic_data<T>::prefixes[]; -+template <typename T> constexpr const char basic_data<T>::left_padding_shifts[]; - template <typename T> --const typename basic_data<T>::digit_pair basic_data<T>::digits[] = { -- {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'}, -- {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'}, -- {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, -- {'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, -- {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'}, -- {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'}, -- {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'}, -- {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'}, -- {'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, -- {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'}, -- {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'}, -- {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'}, -- {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'}, -- {'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, -- {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'}, -- {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'}, -- {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}}; -- --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, \ -- (factor)*1000000000 -- --template <typename T> --const uint64_t basic_data<T>::powers_of_10_64[] = { -- 1, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(1000000000ULL), -- 10000000000000000000ULL}; -- --template <typename T> --const uint32_t basic_data<T>::zero_or_powers_of_10_32[] = {0, -- FMT_POWERS_OF_10(1)}; --template <typename T> --const uint64_t basic_data<T>::zero_or_powers_of_10_64[] = { -- 0, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(1000000000ULL), -- 10000000000000000000ULL}; -- --template <typename T> --const uint32_t basic_data<T>::zero_or_powers_of_10_32_new[] = { -- 0, 0, FMT_POWERS_OF_10(1)}; -- --template <typename T> --const uint64_t basic_data<T>::zero_or_powers_of_10_64_new[] = { -- 0, 0, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(1000000000ULL), -- 10000000000000000000ULL}; -- --// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. --// These are generated by support/compute-powers.py. --template <typename T> --const uint64_t basic_data<T>::grisu_pow10_significands[] = { -- 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, -- 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, -- 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, -- 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, -- 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, -- 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7, -- 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e, -- 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, -- 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, -- 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, -- 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f, -- 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, -- 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, -- 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, -- 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000, -- 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984, -- 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, -- 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, -- 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758, -- 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85, -- 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, -- 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25, -- 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2, -- 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a, -- 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, -- 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129, -- 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85, -- 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, -- 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, --}; -- --// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding --// to significands above. --template <typename T> --const int16_t basic_data<T>::grisu_pow10_exponents[] = { -- -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -- -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, -- -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, -- -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, -- -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, -- 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, -- 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, -- 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066}; -- --template <typename T> --const divtest_table_entry<uint32_t> basic_data<T>::divtest_table_for_pow5_32[] = -- {{0x00000001, 0xffffffff}, {0xcccccccd, 0x33333333}, -- {0xc28f5c29, 0x0a3d70a3}, {0x26e978d5, 0x020c49ba}, -- {0x3afb7e91, 0x0068db8b}, {0x0bcbe61d, 0x0014f8b5}, -- {0x68c26139, 0x000431bd}, {0xae8d46a5, 0x0000d6bf}, -- {0x22e90e21, 0x00002af3}, {0x3a2e9c6d, 0x00000897}, -- {0x3ed61f49, 0x000001b7}}; -- --template <typename T> --const divtest_table_entry<uint64_t> basic_data<T>::divtest_table_for_pow5_64[] = -- {{0x0000000000000001, 0xffffffffffffffff}, -- {0xcccccccccccccccd, 0x3333333333333333}, -- {0x8f5c28f5c28f5c29, 0x0a3d70a3d70a3d70}, -- {0x1cac083126e978d5, 0x020c49ba5e353f7c}, -- {0xd288ce703afb7e91, 0x0068db8bac710cb2}, -- {0x5d4e8fb00bcbe61d, 0x0014f8b588e368f0}, -- {0x790fb65668c26139, 0x000431bde82d7b63}, -- {0xe5032477ae8d46a5, 0x0000d6bf94d5e57a}, -- {0xc767074b22e90e21, 0x00002af31dc46118}, -- {0x8e47ce423a2e9c6d, 0x0000089705f4136b}, -- {0x4fa7f60d3ed61f49, 0x000001b7cdfd9d7b}, -- {0x0fee64690c913975, 0x00000057f5ff85e5}, -- {0x3662e0e1cf503eb1, 0x000000119799812d}, -- {0xa47a2cf9f6433fbd, 0x0000000384b84d09}, -- {0x54186f653140a659, 0x00000000b424dc35}, -- {0x7738164770402145, 0x0000000024075f3d}, -- {0xe4a4d1417cd9a041, 0x000000000734aca5}, -- {0xc75429d9e5c5200d, 0x000000000170ef54}, -- {0xc1773b91fac10669, 0x000000000049c977}, -- {0x26b172506559ce15, 0x00000000000ec1e4}, -- {0xd489e3a9addec2d1, 0x000000000002f394}, -- {0x90e860bb892c8d5d, 0x000000000000971d}, -- {0x502e79bf1b6f4f79, 0x0000000000001e39}, -- {0xdcd618596be30fe5, 0x000000000000060b}}; -- --template <typename T> --const uint64_t basic_data<T>::dragonbox_pow10_significands_64[] = { -- 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f, -- 0xfd87b5f28300ca0e, 0x9e74d1b791e07e49, 0xc612062576589ddb, -- 0xf79687aed3eec552, 0x9abe14cd44753b53, 0xc16d9a0095928a28, -- 0xf1c90080baf72cb2, 0x971da05074da7bef, 0xbce5086492111aeb, -- 0xec1e4a7db69561a6, 0x9392ee8e921d5d08, 0xb877aa3236a4b44a, -- 0xe69594bec44de15c, 0x901d7cf73ab0acda, 0xb424dc35095cd810, -- 0xe12e13424bb40e14, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff, -- 0xdbe6fecebdedd5bf, 0x89705f4136b4a598, 0xabcc77118461cefd, -- 0xd6bf94d5e57a42bd, 0x8637bd05af6c69b6, 0xa7c5ac471b478424, -- 0xd1b71758e219652c, 0x83126e978d4fdf3c, 0xa3d70a3d70a3d70b, -- 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000, -- 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000, -- 0xc350000000000000, 0xf424000000000000, 0x9896800000000000, -- 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000, -- 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000, -- 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000, -- 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, -- 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000, -- 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0, -- 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940984, -- 0xa18f07d736b90be5, 0xc9f2c9cd04674ede, 0xfc6f7c4045812296, -- 0x9dc5ada82b70b59d, 0xc5371912364ce305, 0xf684df56c3e01bc6, -- 0x9a130b963a6c115c, 0xc097ce7bc90715b3, 0xf0bdc21abb48db20, -- 0x96769950b50d88f4, 0xbc143fa4e250eb31, 0xeb194f8e1ae525fd, -- 0x92efd1b8d0cf37be, 0xb7abc627050305ad, 0xe596b7b0c643c719, -- 0x8f7e32ce7bea5c6f, 0xb35dbf821ae4f38b, 0xe0352f62a19e306e}; -- --template <typename T> --const uint128_wrapper basic_data<T>::dragonbox_pow10_significands_128[] = { --#if FMT_USE_FULL_CACHE_DRAGONBOX -- {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, -- {0x9faacf3df73609b1, 0x77b191618c54e9ad}, -- {0xc795830d75038c1d, 0xd59df5b9ef6a2418}, -- {0xf97ae3d0d2446f25, 0x4b0573286b44ad1e}, -- {0x9becce62836ac577, 0x4ee367f9430aec33}, -- {0xc2e801fb244576d5, 0x229c41f793cda740}, -- {0xf3a20279ed56d48a, 0x6b43527578c11110}, -- {0x9845418c345644d6, 0x830a13896b78aaaa}, -- {0xbe5691ef416bd60c, 0x23cc986bc656d554}, -- {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9}, -- {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa}, -- {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54}, -- {0xe858ad248f5c22c9, 0xd1b3400f8f9cff69}, -- {0x91376c36d99995be, 0x23100809b9c21fa2}, -- {0xb58547448ffffb2d, 0xabd40a0c2832a78b}, -- {0xe2e69915b3fff9f9, 0x16c90c8f323f516d}, -- {0x8dd01fad907ffc3b, 0xae3da7d97f6792e4}, -- {0xb1442798f49ffb4a, 0x99cd11cfdf41779d}, -- {0xdd95317f31c7fa1d, 0x40405643d711d584}, -- {0x8a7d3eef7f1cfc52, 0x482835ea666b2573}, -- {0xad1c8eab5ee43b66, 0xda3243650005eed0}, -- {0xd863b256369d4a40, 0x90bed43e40076a83}, -- {0x873e4f75e2224e68, 0x5a7744a6e804a292}, -- {0xa90de3535aaae202, 0x711515d0a205cb37}, -- {0xd3515c2831559a83, 0x0d5a5b44ca873e04}, -- {0x8412d9991ed58091, 0xe858790afe9486c3}, -- {0xa5178fff668ae0b6, 0x626e974dbe39a873}, -- {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, -- {0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a}, -- {0xa139029f6a239f72, 0x1c1fffc1ebc44e81}, -- {0xc987434744ac874e, 0xa327ffb266b56221}, -- {0xfbe9141915d7a922, 0x4bf1ff9f0062baa9}, -- {0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa}, -- {0xc4ce17b399107c22, 0xcb550fb4384d21d4}, -- {0xf6019da07f549b2b, 0x7e2a53a146606a49}, -- {0x99c102844f94e0fb, 0x2eda7444cbfc426e}, -- {0xc0314325637a1939, 0xfa911155fefb5309}, -- {0xf03d93eebc589f88, 0x793555ab7eba27cb}, -- {0x96267c7535b763b5, 0x4bc1558b2f3458df}, -- {0xbbb01b9283253ca2, 0x9eb1aaedfb016f17}, -- {0xea9c227723ee8bcb, 0x465e15a979c1cadd}, -- {0x92a1958a7675175f, 0x0bfacd89ec191eca}, -- {0xb749faed14125d36, 0xcef980ec671f667c}, -- {0xe51c79a85916f484, 0x82b7e12780e7401b}, -- {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811}, -- {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16}, -- {0xdfbdcece67006ac9, 0x67a791e093e1d49b}, -- {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1}, -- {0xaecc49914078536d, 0x58fae9f773886e19}, -- {0xda7f5bf590966848, 0xaf39a475506a899f}, -- {0x888f99797a5e012d, 0x6d8406c952429604}, -- {0xaab37fd7d8f58178, 0xc8e5087ba6d33b84}, -- {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65}, -- {0x855c3be0a17fcd26, 0x5cf2eea09a550680}, -- {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, -- {0xd0601d8efc57b08b, 0xf13b94daf124da27}, -- {0x823c12795db6ce57, 0x76c53d08d6b70859}, -- {0xa2cb1717b52481ed, 0x54768c4b0c64ca6f}, -- {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a}, -- {0xfe5d54150b090b02, 0xd3f93b35435d7c4d}, -- {0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0}, -- {0xc6b8e9b0709f109a, 0x359ab6419ca1091c}, -- {0xf867241c8cc6d4c0, 0xc30163d203c94b63}, -- {0x9b407691d7fc44f8, 0x79e0de63425dcf1e}, -- {0xc21094364dfb5636, 0x985915fc12f542e5}, -- {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e}, -- {0x979cf3ca6cec5b5a, 0xa705992ceecf9c43}, -- {0xbd8430bd08277231, 0x50c6ff782a838354}, -- {0xece53cec4a314ebd, 0xa4f8bf5635246429}, -- {0x940f4613ae5ed136, 0x871b7795e136be9a}, -- {0xb913179899f68584, 0x28e2557b59846e40}, -- {0xe757dd7ec07426e5, 0x331aeada2fe589d0}, -- {0x9096ea6f3848984f, 0x3ff0d2c85def7622}, -- {0xb4bca50b065abe63, 0x0fed077a756b53aa}, -- {0xe1ebce4dc7f16dfb, 0xd3e8495912c62895}, -- {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d}, -- {0xb080392cc4349dec, 0xbd8d794d96aacfb4}, -- {0xdca04777f541c567, 0xecf0d7a0fc5583a1}, -- {0x89e42caaf9491b60, 0xf41686c49db57245}, -- {0xac5d37d5b79b6239, 0x311c2875c522ced6}, -- {0xd77485cb25823ac7, 0x7d633293366b828c}, -- {0x86a8d39ef77164bc, 0xae5dff9c02033198}, -- {0xa8530886b54dbdeb, 0xd9f57f830283fdfd}, -- {0xd267caa862a12d66, 0xd072df63c324fd7c}, -- {0x8380dea93da4bc60, 0x4247cb9e59f71e6e}, -- {0xa46116538d0deb78, 0x52d9be85f074e609}, -- {0xcd795be870516656, 0x67902e276c921f8c}, -- {0x806bd9714632dff6, 0x00ba1cd8a3db53b7}, -- {0xa086cfcd97bf97f3, 0x80e8a40eccd228a5}, -- {0xc8a883c0fdaf7df0, 0x6122cd128006b2ce}, -- {0xfad2a4b13d1b5d6c, 0x796b805720085f82}, -- {0x9cc3a6eec6311a63, 0xcbe3303674053bb1}, -- {0xc3f490aa77bd60fc, 0xbedbfc4411068a9d}, -- {0xf4f1b4d515acb93b, 0xee92fb5515482d45}, -- {0x991711052d8bf3c5, 0x751bdd152d4d1c4b}, -- {0xbf5cd54678eef0b6, 0xd262d45a78a0635e}, -- {0xef340a98172aace4, 0x86fb897116c87c35}, -- {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1}, -- {0xbae0a846d2195712, 0x8974836059cca10a}, -- {0xe998d258869facd7, 0x2bd1a438703fc94c}, -- {0x91ff83775423cc06, 0x7b6306a34627ddd0}, -- {0xb67f6455292cbf08, 0x1a3bc84c17b1d543}, -- {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94}, -- {0x8e938662882af53e, 0x547eb47b7282ee9d}, -- {0xb23867fb2a35b28d, 0xe99e619a4f23aa44}, -- {0xdec681f9f4c31f31, 0x6405fa00e2ec94d5}, -- {0x8b3c113c38f9f37e, 0xde83bc408dd3dd05}, -- {0xae0b158b4738705e, 0x9624ab50b148d446}, -- {0xd98ddaee19068c76, 0x3badd624dd9b0958}, -- {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7}, -- {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d}, -- {0xd47487cc8470652b, 0x7647c32000696720}, -- {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074}, -- {0xa5fb0a17c777cf09, 0xf468107100525891}, -- {0xcf79cc9db955c2cc, 0x7182148d4066eeb5}, -- {0x81ac1fe293d599bf, 0xc6f14cd848405531}, -- {0xa21727db38cb002f, 0xb8ada00e5a506a7d}, -- {0xca9cf1d206fdc03b, 0xa6d90811f0e4851d}, -- {0xfd442e4688bd304a, 0x908f4a166d1da664}, -- {0x9e4a9cec15763e2e, 0x9a598e4e043287ff}, -- {0xc5dd44271ad3cdba, 0x40eff1e1853f29fe}, -- {0xf7549530e188c128, 0xd12bee59e68ef47d}, -- {0x9a94dd3e8cf578b9, 0x82bb74f8301958cf}, -- {0xc13a148e3032d6e7, 0xe36a52363c1faf02}, -- {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2}, -- {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba}, -- {0xbcb2b812db11a5de, 0x7415d448f6b6f0e8}, -- {0xebdf661791d60f56, 0x111b495b3464ad22}, -- {0x936b9fcebb25c995, 0xcab10dd900beec35}, -- {0xb84687c269ef3bfb, 0x3d5d514f40eea743}, -- {0xe65829b3046b0afa, 0x0cb4a5a3112a5113}, -- {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac}, -- {0xb3f4e093db73a093, 0x59ed216765690f57}, -- {0xe0f218b8d25088b8, 0x306869c13ec3532d}, -- {0x8c974f7383725573, 0x1e414218c73a13fc}, -- {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, -- {0xdbac6c247d62a583, 0xdf45f746b74abf3a}, -- {0x894bc396ce5da772, 0x6b8bba8c328eb784}, -- {0xab9eb47c81f5114f, 0x066ea92f3f326565}, -- {0xd686619ba27255a2, 0xc80a537b0efefebe}, -- {0x8613fd0145877585, 0xbd06742ce95f5f37}, -- {0xa798fc4196e952e7, 0x2c48113823b73705}, -- {0xd17f3b51fca3a7a0, 0xf75a15862ca504c6}, -- {0x82ef85133de648c4, 0x9a984d73dbe722fc}, -- {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb}, -- {0xcc963fee10b7d1b3, 0x318df905079926a9}, -- {0xffbbcfe994e5c61f, 0xfdf17746497f7053}, -- {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634}, -- {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1}, -- {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1}, -- {0x9c1661a651213e2d, 0x06bea10ca65c084f}, -- {0xc31bfa0fe5698db8, 0x486e494fcff30a63}, -- {0xf3e2f893dec3f126, 0x5a89dba3c3efccfb}, -- {0x986ddb5c6b3a76b7, 0xf89629465a75e01d}, -- {0xbe89523386091465, 0xf6bbb397f1135824}, -- {0xee2ba6c0678b597f, 0x746aa07ded582e2d}, -- {0x94db483840b717ef, 0xa8c2a44eb4571cdd}, -- {0xba121a4650e4ddeb, 0x92f34d62616ce414}, -- {0xe896a0d7e51e1566, 0x77b020baf9c81d18}, -- {0x915e2486ef32cd60, 0x0ace1474dc1d122f}, -- {0xb5b5ada8aaff80b8, 0x0d819992132456bb}, -- {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a}, -- {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, -- {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3}, -- {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf}, -- {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c}, -- {0xad4ab7112eb3929d, 0x86c16c98d2c953c7}, -- {0xd89d64d57a607744, 0xe871c7bf077ba8b8}, -- {0x87625f056c7c4a8b, 0x11471cd764ad4973}, -- {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0}, -- {0xd389b47879823479, 0x4aff1d108d4ec2c4}, -- {0x843610cb4bf160cb, 0xcedf722a585139bb}, -- {0xa54394fe1eedb8fe, 0xc2974eb4ee658829}, -- {0xce947a3da6a9273e, 0x733d226229feea33}, -- {0x811ccc668829b887, 0x0806357d5a3f5260}, -- {0xa163ff802a3426a8, 0xca07c2dcb0cf26f8}, -- {0xc9bcff6034c13052, 0xfc89b393dd02f0b6}, -- {0xfc2c3f3841f17c67, 0xbbac2078d443ace3}, -- {0x9d9ba7832936edc0, 0xd54b944b84aa4c0e}, -- {0xc5029163f384a931, 0x0a9e795e65d4df12}, -- {0xf64335bcf065d37d, 0x4d4617b5ff4a16d6}, -- {0x99ea0196163fa42e, 0x504bced1bf8e4e46}, -- {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7}, -- {0xf07da27a82c37088, 0x5d767327bb4e5a4d}, -- {0x964e858c91ba2655, 0x3a6a07f8d510f870}, -- {0xbbe226efb628afea, 0x890489f70a55368c}, -- {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f}, -- {0x92c8ae6b464fc96f, 0x3b0b8bc90012929e}, -- {0xb77ada0617e3bbcb, 0x09ce6ebb40173745}, -- {0xe55990879ddcaabd, 0xcc420a6a101d0516}, -- {0x8f57fa54c2a9eab6, 0x9fa946824a12232e}, -- {0xb32df8e9f3546564, 0x47939822dc96abfa}, -- {0xdff9772470297ebd, 0x59787e2b93bc56f8}, -- {0x8bfbea76c619ef36, 0x57eb4edb3c55b65b}, -- {0xaefae51477a06b03, 0xede622920b6b23f2}, -- {0xdab99e59958885c4, 0xe95fab368e45ecee}, -- {0x88b402f7fd75539b, 0x11dbcb0218ebb415}, -- {0xaae103b5fcd2a881, 0xd652bdc29f26a11a}, -- {0xd59944a37c0752a2, 0x4be76d3346f04960}, -- {0x857fcae62d8493a5, 0x6f70a4400c562ddc}, -- {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953}, -- {0xd097ad07a71f26b2, 0x7e2000a41346a7a8}, -- {0x825ecc24c873782f, 0x8ed400668c0c28c9}, -- {0xa2f67f2dfa90563b, 0x728900802f0f32fb}, -- {0xcbb41ef979346bca, 0x4f2b40a03ad2ffba}, -- {0xfea126b7d78186bc, 0xe2f610c84987bfa9}, -- {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca}, -- {0xc6ede63fa05d3143, 0x91503d1c79720dbc}, -- {0xf8a95fcf88747d94, 0x75a44c6397ce912b}, -- {0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb}, -- {0xc24452da229b021b, 0xfbe85badce996169}, -- {0xf2d56790ab41c2a2, 0xfae27299423fb9c4}, -- {0x97c560ba6b0919a5, 0xdccd879fc967d41b}, -- {0xbdb6b8e905cb600f, 0x5400e987bbc1c921}, -- {0xed246723473e3813, 0x290123e9aab23b69}, -- {0x9436c0760c86e30b, 0xf9a0b6720aaf6522}, -- {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, -- {0xe7958cb87392c2c2, 0xb60b1d1230b20e05}, -- {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3}, -- {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4}, -- {0xe2280b6c20dd5232, 0x25c6da63c38de1b1}, -- {0x8d590723948a535f, 0x579c487e5a38ad0f}, -- {0xb0af48ec79ace837, 0x2d835a9df0c6d852}, -- {0xdcdb1b2798182244, 0xf8e431456cf88e66}, -- {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900}, -- {0xac8b2d36eed2dac5, 0xe272467e3d222f40}, -- {0xd7adf884aa879177, 0x5b0ed81dcc6abb10}, -- {0x86ccbb52ea94baea, 0x98e947129fc2b4ea}, -- {0xa87fea27a539e9a5, 0x3f2398d747b36225}, -- {0xd29fe4b18e88640e, 0x8eec7f0d19a03aae}, -- {0x83a3eeeef9153e89, 0x1953cf68300424ad}, -- {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8}, -- {0xcdb02555653131b6, 0x3792f412cb06794e}, -- {0x808e17555f3ebf11, 0xe2bbd88bbee40bd1}, -- {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5}, -- {0xc8de047564d20a8b, 0xf245825a5a445276}, -- {0xfb158592be068d2e, 0xeed6e2f0f0d56713}, -- {0x9ced737bb6c4183d, 0x55464dd69685606c}, -- {0xc428d05aa4751e4c, 0xaa97e14c3c26b887}, -- {0xf53304714d9265df, 0xd53dd99f4b3066a9}, -- {0x993fe2c6d07b7fab, 0xe546a8038efe402a}, -- {0xbf8fdb78849a5f96, 0xde98520472bdd034}, -- {0xef73d256a5c0f77c, 0x963e66858f6d4441}, -- {0x95a8637627989aad, 0xdde7001379a44aa9}, -- {0xbb127c53b17ec159, 0x5560c018580d5d53}, -- {0xe9d71b689dde71af, 0xaab8f01e6e10b4a7}, -- {0x9226712162ab070d, 0xcab3961304ca70e9}, -- {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23}, -- {0xe45c10c42a2b3b05, 0x8cb89a7db77c506b}, -- {0x8eb98a7a9a5b04e3, 0x77f3608e92adb243}, -- {0xb267ed1940f1c61c, 0x55f038b237591ed4}, -- {0xdf01e85f912e37a3, 0x6b6c46dec52f6689}, -- {0x8b61313bbabce2c6, 0x2323ac4b3b3da016}, -- {0xae397d8aa96c1b77, 0xabec975e0a0d081b}, -- {0xd9c7dced53c72255, 0x96e7bd358c904a22}, -- {0x881cea14545c7575, 0x7e50d64177da2e55}, -- {0xaa242499697392d2, 0xdde50bd1d5d0b9ea}, -- {0xd4ad2dbfc3d07787, 0x955e4ec64b44e865}, -- {0x84ec3c97da624ab4, 0xbd5af13bef0b113f}, -- {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f}, -- {0xcfb11ead453994ba, 0x67de18eda5814af3}, -- {0x81ceb32c4b43fcf4, 0x80eacf948770ced8}, -- {0xa2425ff75e14fc31, 0xa1258379a94d028e}, -- {0xcad2f7f5359a3b3e, 0x096ee45813a04331}, -- {0xfd87b5f28300ca0d, 0x8bca9d6e188853fd}, -- {0x9e74d1b791e07e48, 0x775ea264cf55347e}, -- {0xc612062576589dda, 0x95364afe032a819e}, -- {0xf79687aed3eec551, 0x3a83ddbd83f52205}, -- {0x9abe14cd44753b52, 0xc4926a9672793543}, -- {0xc16d9a0095928a27, 0x75b7053c0f178294}, -- {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, -- {0x971da05074da7bee, 0xd3f6fc16ebca5e04}, -- {0xbce5086492111aea, 0x88f4bb1ca6bcf585}, -- {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6}, -- {0x9392ee8e921d5d07, 0x3aff322e62439fd0}, -- {0xb877aa3236a4b449, 0x09befeb9fad487c3}, -- {0xe69594bec44de15b, 0x4c2ebe687989a9b4}, -- {0x901d7cf73ab0acd9, 0x0f9d37014bf60a11}, -- {0xb424dc35095cd80f, 0x538484c19ef38c95}, -- {0xe12e13424bb40e13, 0x2865a5f206b06fba}, -- {0x8cbccc096f5088cb, 0xf93f87b7442e45d4}, -- {0xafebff0bcb24aafe, 0xf78f69a51539d749}, -- {0xdbe6fecebdedd5be, 0xb573440e5a884d1c}, -- {0x89705f4136b4a597, 0x31680a88f8953031}, -- {0xabcc77118461cefc, 0xfdc20d2b36ba7c3e}, -- {0xd6bf94d5e57a42bc, 0x3d32907604691b4d}, -- {0x8637bd05af6c69b5, 0xa63f9a49c2c1b110}, -- {0xa7c5ac471b478423, 0x0fcf80dc33721d54}, -- {0xd1b71758e219652b, 0xd3c36113404ea4a9}, -- {0x83126e978d4fdf3b, 0x645a1cac083126ea}, -- {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4}, -- {0xcccccccccccccccc, 0xcccccccccccccccd}, -- {0x8000000000000000, 0x0000000000000000}, -- {0xa000000000000000, 0x0000000000000000}, -- {0xc800000000000000, 0x0000000000000000}, -- {0xfa00000000000000, 0x0000000000000000}, -- {0x9c40000000000000, 0x0000000000000000}, -- {0xc350000000000000, 0x0000000000000000}, -- {0xf424000000000000, 0x0000000000000000}, -- {0x9896800000000000, 0x0000000000000000}, -- {0xbebc200000000000, 0x0000000000000000}, -- {0xee6b280000000000, 0x0000000000000000}, -- {0x9502f90000000000, 0x0000000000000000}, -- {0xba43b74000000000, 0x0000000000000000}, -- {0xe8d4a51000000000, 0x0000000000000000}, -- {0x9184e72a00000000, 0x0000000000000000}, -- {0xb5e620f480000000, 0x0000000000000000}, -- {0xe35fa931a0000000, 0x0000000000000000}, -- {0x8e1bc9bf04000000, 0x0000000000000000}, -- {0xb1a2bc2ec5000000, 0x0000000000000000}, -- {0xde0b6b3a76400000, 0x0000000000000000}, -- {0x8ac7230489e80000, 0x0000000000000000}, -- {0xad78ebc5ac620000, 0x0000000000000000}, -- {0xd8d726b7177a8000, 0x0000000000000000}, -- {0x878678326eac9000, 0x0000000000000000}, -- {0xa968163f0a57b400, 0x0000000000000000}, -- {0xd3c21bcecceda100, 0x0000000000000000}, -- {0x84595161401484a0, 0x0000000000000000}, -- {0xa56fa5b99019a5c8, 0x0000000000000000}, -- {0xcecb8f27f4200f3a, 0x0000000000000000}, -- {0x813f3978f8940984, 0x4000000000000000}, -- {0xa18f07d736b90be5, 0x5000000000000000}, -- {0xc9f2c9cd04674ede, 0xa400000000000000}, -- {0xfc6f7c4045812296, 0x4d00000000000000}, -- {0x9dc5ada82b70b59d, 0xf020000000000000}, -- {0xc5371912364ce305, 0x6c28000000000000}, -- {0xf684df56c3e01bc6, 0xc732000000000000}, -- {0x9a130b963a6c115c, 0x3c7f400000000000}, -- {0xc097ce7bc90715b3, 0x4b9f100000000000}, -- {0xf0bdc21abb48db20, 0x1e86d40000000000}, -- {0x96769950b50d88f4, 0x1314448000000000}, -- {0xbc143fa4e250eb31, 0x17d955a000000000}, -- {0xeb194f8e1ae525fd, 0x5dcfab0800000000}, -- {0x92efd1b8d0cf37be, 0x5aa1cae500000000}, -- {0xb7abc627050305ad, 0xf14a3d9e40000000}, -- {0xe596b7b0c643c719, 0x6d9ccd05d0000000}, -- {0x8f7e32ce7bea5c6f, 0xe4820023a2000000}, -- {0xb35dbf821ae4f38b, 0xdda2802c8a800000}, -- {0xe0352f62a19e306e, 0xd50b2037ad200000}, -- {0x8c213d9da502de45, 0x4526f422cc340000}, -- {0xaf298d050e4395d6, 0x9670b12b7f410000}, -- {0xdaf3f04651d47b4c, 0x3c0cdd765f114000}, -- {0x88d8762bf324cd0f, 0xa5880a69fb6ac800}, -- {0xab0e93b6efee0053, 0x8eea0d047a457a00}, -- {0xd5d238a4abe98068, 0x72a4904598d6d880}, -- {0x85a36366eb71f041, 0x47a6da2b7f864750}, -- {0xa70c3c40a64e6c51, 0x999090b65f67d924}, -- {0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d}, -- {0x82818f1281ed449f, 0xbff8f10e7a8921a4}, -- {0xa321f2d7226895c7, 0xaff72d52192b6a0d}, -- {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490}, -- {0xfee50b7025c36a08, 0x02f236d04753d5b4}, -- {0x9f4f2726179a2245, 0x01d762422c946590}, -- {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5}, -- {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2}, -- {0x9b934c3b330c8577, 0x63cc55f49f88eb2f}, -- {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb}, -- {0xf316271c7fc3908a, 0x8bef464e3945ef7a}, -- {0x97edd871cfda3a56, 0x97758bf0e3cbb5ac}, -- {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317}, -- {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd}, -- {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a}, -- {0xb975d6b6ee39e436, 0xb3e2fd538e122b44}, -- {0xe7d34c64a9c85d44, 0x60dbbca87196b616}, -- {0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd}, -- {0xb51d13aea4a488dd, 0x6babab6398bdbe41}, -- {0xe264589a4dcdab14, 0xc696963c7eed2dd1}, -- {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2}, -- {0xb0de65388cc8ada8, 0x3b25a55f43294bcb}, -- {0xdd15fe86affad912, 0x49ef0eb713f39ebe}, -- {0x8a2dbf142dfcc7ab, 0x6e3569326c784337}, -- {0xacb92ed9397bf996, 0x49c2c37f07965404}, -- {0xd7e77a8f87daf7fb, 0xdc33745ec97be906}, -- {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3}, -- {0xa8acd7c0222311bc, 0xc40832ea0d68ce0c}, -- {0xd2d80db02aabd62b, 0xf50a3fa490c30190}, -- {0x83c7088e1aab65db, 0x792667c6da79e0fa}, -- {0xa4b8cab1a1563f52, 0x577001b891185938}, -- {0xcde6fd5e09abcf26, 0xed4c0226b55e6f86}, -- {0x80b05e5ac60b6178, 0x544f8158315b05b4}, -- {0xa0dc75f1778e39d6, 0x696361ae3db1c721}, -- {0xc913936dd571c84c, 0x03bc3a19cd1e38e9}, -- {0xfb5878494ace3a5f, 0x04ab48a04065c723}, -- {0x9d174b2dcec0e47b, 0x62eb0d64283f9c76}, -- {0xc45d1df942711d9a, 0x3ba5d0bd324f8394}, -- {0xf5746577930d6500, 0xca8f44ec7ee36479}, -- {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb}, -- {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e}, -- {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e}, -- {0x95d04aee3b80ece5, 0xbba1f1d158724a12}, -- {0xbb445da9ca61281f, 0x2a8a6e45ae8edc97}, -- {0xea1575143cf97226, 0xf52d09d71a3293bd}, -- {0x924d692ca61be758, 0x593c2626705f9c56}, -- {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c}, -- {0xe498f455c38b997a, 0x0b6dfb9c0f956447}, -- {0x8edf98b59a373fec, 0x4724bd4189bd5eac}, -- {0xb2977ee300c50fe7, 0x58edec91ec2cb657}, -- {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed}, -- {0x8b865b215899f46c, 0xbd79e0d20082ee74}, -- {0xae67f1e9aec07187, 0xecd8590680a3aa11}, -- {0xda01ee641a708de9, 0xe80e6f4820cc9495}, -- {0x884134fe908658b2, 0x3109058d147fdcdd}, -- {0xaa51823e34a7eede, 0xbd4b46f0599fd415}, -- {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a}, -- {0x850fadc09923329e, 0x03e2cf6bc604ddb0}, -- {0xa6539930bf6bff45, 0x84db8346b786151c}, -- {0xcfe87f7cef46ff16, 0xe612641865679a63}, -- {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e}, -- {0xa26da3999aef7749, 0xe3be5e330f38f09d}, -- {0xcb090c8001ab551c, 0x5cadf5bfd3072cc5}, -- {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6}, -- {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa}, -- {0xc646d63501a1511d, 0xb281e1fd541501b8}, -- {0xf7d88bc24209a565, 0x1f225a7ca91a4226}, -- {0x9ae757596946075f, 0x3375788de9b06958}, -- {0xc1a12d2fc3978937, 0x0052d6b1641c83ae}, -- {0xf209787bb47d6b84, 0xc0678c5dbd23a49a}, -- {0x9745eb4d50ce6332, 0xf840b7ba963646e0}, -- {0xbd176620a501fbff, 0xb650e5a93bc3d898}, -- {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe}, -- {0x93ba47c980e98cdf, 0xc66f336c36b10137}, -- {0xb8a8d9bbe123f017, 0xb80b0047445d4184}, -- {0xe6d3102ad96cec1d, 0xa60dc059157491e5}, -- {0x9043ea1ac7e41392, 0x87c89837ad68db2f}, -- {0xb454e4a179dd1877, 0x29babe4598c311fb}, -- {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a}, -- {0x8ce2529e2734bb1d, 0x1899e4a65f58660c}, -- {0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f}, -- {0xdc21a1171d42645d, 0x76707543f4fa1f73}, -- {0x899504ae72497eba, 0x6a06494a791c53a8}, -- {0xabfa45da0edbde69, 0x0487db9d17636892}, -- {0xd6f8d7509292d603, 0x45a9d2845d3c42b6}, -- {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b2}, -- {0xa7f26836f282b732, 0x8e6cac7768d7141e}, -- {0xd1ef0244af2364ff, 0x3207d795430cd926}, -- {0x8335616aed761f1f, 0x7f44e6bd49e807b8}, -- {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6}, -- {0xcd036837130890a1, 0x36dba887c37a8c0f}, -- {0x802221226be55a64, 0xc2494954da2c9789}, -- {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c}, -- {0xc83553c5c8965d3d, 0x6f92829494e5acc7}, -- {0xfa42a8b73abbf48c, 0xcb772339ba1f17f9}, -- {0x9c69a97284b578d7, 0xff2a760414536efb}, -- {0xc38413cf25e2d70d, 0xfef5138519684aba}, -- {0xf46518c2ef5b8cd1, 0x7eb258665fc25d69}, -- {0x98bf2f79d5993802, 0xef2f773ffbd97a61}, -- {0xbeeefb584aff8603, 0xaafb550ffacfd8fa}, -- {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38}, -- {0x952ab45cfa97a0b2, 0xdd945a747bf26183}, -- {0xba756174393d88df, 0x94f971119aeef9e4}, -- {0xe912b9d1478ceb17, 0x7a37cd5601aab85d}, -- {0x91abb422ccb812ee, 0xac62e055c10ab33a}, -- {0xb616a12b7fe617aa, 0x577b986b314d6009}, -- {0xe39c49765fdf9d94, 0xed5a7e85fda0b80b}, -- {0x8e41ade9fbebc27d, 0x14588f13be847307}, -- {0xb1d219647ae6b31c, 0x596eb2d8ae258fc8}, -- {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb}, -- {0x8aec23d680043bee, 0x25de7bb9480d5854}, -- {0xada72ccc20054ae9, 0xaf561aa79a10ae6a}, -- {0xd910f7ff28069da4, 0x1b2ba1518094da04}, -- {0x87aa9aff79042286, 0x90fb44d2f05d0842}, -- {0xa99541bf57452b28, 0x353a1607ac744a53}, -- {0xd3fa922f2d1675f2, 0x42889b8997915ce8}, -- {0x847c9b5d7c2e09b7, 0x69956135febada11}, -- {0xa59bc234db398c25, 0x43fab9837e699095}, -- {0xcf02b2c21207ef2e, 0x94f967e45e03f4bb}, -- {0x8161afb94b44f57d, 0x1d1be0eebac278f5}, -- {0xa1ba1ba79e1632dc, 0x6462d92a69731732}, -- {0xca28a291859bbf93, 0x7d7b8f7503cfdcfe}, -- {0xfcb2cb35e702af78, 0x5cda735244c3d43e}, -- {0x9defbf01b061adab, 0x3a0888136afa64a7}, -- {0xc56baec21c7a1916, 0x088aaa1845b8fdd0}, -- {0xf6c69a72a3989f5b, 0x8aad549e57273d45}, -- {0x9a3c2087a63f6399, 0x36ac54e2f678864b}, -- {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd}, -- {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5}, -- {0x969eb7c47859e743, 0x9f644ae5a4b1b325}, -- {0xbc4665b596706114, 0x873d5d9f0dde1fee}, -- {0xeb57ff22fc0c7959, 0xa90cb506d155a7ea}, -- {0x9316ff75dd87cbd8, 0x09a7f12442d588f2}, -- {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb2f}, -- {0xe5d3ef282a242e81, 0x8f1668c8a86da5fa}, -- {0x8fa475791a569d10, 0xf96e017d694487bc}, -- {0xb38d92d760ec4455, 0x37c981dcc395a9ac}, -- {0xe070f78d3927556a, 0x85bbe253f47b1417}, -- {0x8c469ab843b89562, 0x93956d7478ccec8e}, -- {0xaf58416654a6babb, 0x387ac8d1970027b2}, -- {0xdb2e51bfe9d0696a, 0x06997b05fcc0319e}, -- {0x88fcf317f22241e2, 0x441fece3bdf81f03}, -- {0xab3c2fddeeaad25a, 0xd527e81cad7626c3}, -- {0xd60b3bd56a5586f1, 0x8a71e223d8d3b074}, -- {0x85c7056562757456, 0xf6872d5667844e49}, -- {0xa738c6bebb12d16c, 0xb428f8ac016561db}, -- {0xd106f86e69d785c7, 0xe13336d701beba52}, -- {0x82a45b450226b39c, 0xecc0024661173473}, -- {0xa34d721642b06084, 0x27f002d7f95d0190}, -- {0xcc20ce9bd35c78a5, 0x31ec038df7b441f4}, -- {0xff290242c83396ce, 0x7e67047175a15271}, -- {0x9f79a169bd203e41, 0x0f0062c6e984d386}, -- {0xc75809c42c684dd1, 0x52c07b78a3e60868}, -- {0xf92e0c3537826145, 0xa7709a56ccdf8a82}, -- {0x9bbcc7a142b17ccb, 0x88a66076400bb691}, -- {0xc2abf989935ddbfe, 0x6acff893d00ea435}, -- {0xf356f7ebf83552fe, 0x0583f6b8c4124d43}, -- {0x98165af37b2153de, 0xc3727a337a8b704a}, -- {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c}, -- {0xeda2ee1c7064130c, 0x1162def06f79df73}, -- {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8}, -- {0xb9a74a0637ce2ee1, 0x6d953e2bd7173692}, -- {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437}, -- {0x910ab1d4db9914a0, 0x1d9c9892400a22a2}, -- {0xb54d5e4a127f59c8, 0x2503beb6d00cab4b}, -- {0xe2a0b5dc971f303a, 0x2e44ae64840fd61d}, -- {0x8da471a9de737e24, 0x5ceaecfed289e5d2}, -- {0xb10d8e1456105dad, 0x7425a83e872c5f47}, -- {0xdd50f1996b947518, 0xd12f124e28f77719}, -- {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f}, -- {0xace73cbfdc0bfb7b, 0x636cc64d1001550b}, -- {0xd8210befd30efa5a, 0x3c47f7e05401aa4e}, -- {0x8714a775e3e95c78, 0x65acfaec34810a71}, -- {0xa8d9d1535ce3b396, 0x7f1839a741a14d0d}, -- {0xd31045a8341ca07c, 0x1ede48111209a050}, -- {0x83ea2b892091e44d, 0x934aed0aab460432}, -- {0xa4e4b66b68b65d60, 0xf81da84d5617853f}, -- {0xce1de40642e3f4b9, 0x36251260ab9d668e}, -- {0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019}, -- {0xa1075a24e4421730, 0xb24cf65b8612f81f}, -- {0xc94930ae1d529cfc, 0xdee033f26797b627}, -- {0xfb9b7cd9a4a7443c, 0x169840ef017da3b1}, -- {0x9d412e0806e88aa5, 0x8e1f289560ee864e}, -- {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2}, -- {0xf5b5d7ec8acb58a2, 0xae10af696774b1db}, -- {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29}, -- {0xbff610b0cc6edd3f, 0x17fd090a58d32af3}, -- {0xeff394dcff8a948e, 0xddfc4b4cef07f5b0}, -- {0x95f83d0a1fb69cd9, 0x4abdaf101564f98e}, -- {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1}, -- {0xea53df5fd18d5513, 0x84c86189216dc5ed}, -- {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4}, -- {0xb7118682dbb66a77, 0x3fbc8c33221dc2a1}, -- {0xe4d5e82392a40515, 0x0fabaf3feaa5334a}, -- {0x8f05b1163ba6832d, 0x29cb4d87f2a7400e}, -- {0xb2c71d5bca9023f8, 0x743e20e9ef511012}, -- {0xdf78e4b2bd342cf6, 0x914da9246b255416}, -- {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e}, -- {0xae9672aba3d0c320, 0xa184ac2473b529b1}, -- {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e}, -- {0x8865899617fb1871, 0x7e2fa67c7a658892}, -- {0xaa7eebfb9df9de8d, 0xddbb901b98feeab7}, -- {0xd51ea6fa85785631, 0x552a74227f3ea565}, -- {0x8533285c936b35de, 0xd53a88958f87275f}, -- {0xa67ff273b8460356, 0x8a892abaf368f137}, -- {0xd01fef10a657842c, 0x2d2b7569b0432d85}, -- {0x8213f56a67f6b29b, 0x9c3b29620e29fc73}, -- {0xa298f2c501f45f42, 0x8349f3ba91b47b8f}, -- {0xcb3f2f7642717713, 0x241c70a936219a73}, -- {0xfe0efb53d30dd4d7, 0xed238cd383aa0110}, -- {0x9ec95d1463e8a506, 0xf4363804324a40aa}, -- {0xc67bb4597ce2ce48, 0xb143c6053edcd0d5}, -- {0xf81aa16fdc1b81da, 0xdd94b7868e94050a}, -- {0x9b10a4e5e9913128, 0xca7cf2b4191c8326}, -- {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0}, -- {0xf24a01a73cf2dccf, 0xbc633b39673c8cec}, -- {0x976e41088617ca01, 0xd5be0503e085d813}, -- {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18}, -- {0xec9c459d51852ba2, 0xddf8e7d60ed1219e}, -- {0x93e1ab8252f33b45, 0xcabb90e5c942b503}, -- {0xb8da1662e7b00a17, 0x3d6a751f3b936243}, -- {0xe7109bfba19c0c9d, 0x0cc512670a783ad4}, -- {0x906a617d450187e2, 0x27fb2b80668b24c5}, -- {0xb484f9dc9641e9da, 0xb1f9f660802dedf6}, -- {0xe1a63853bbd26451, 0x5e7873f8a0396973}, -- {0x8d07e33455637eb2, 0xdb0b487b6423e1e8}, -- {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62}, -- {0xdc5c5301c56b75f7, 0x7641a140cc7810fb}, -- {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d}, -- {0xac2820d9623bf429, 0x546345fa9fbdcd44}, -- {0xd732290fbacaf133, 0xa97c177947ad4095}, -- {0x867f59a9d4bed6c0, 0x49ed8eabcccc485d}, -- {0xa81f301449ee8c70, 0x5c68f256bfff5a74}, -- {0xd226fc195c6a2f8c, 0x73832eec6fff3111}, -- {0x83585d8fd9c25db7, 0xc831fd53c5ff7eab}, -- {0xa42e74f3d032f525, 0xba3e7ca8b77f5e55}, -- {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb}, -- {0x80444b5e7aa7cf85, 0x7980d163cf5b81b3}, -- {0xa0555e361951c366, 0xd7e105bcc332621f}, -- {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7}, -- {0xfa856334878fc150, 0xb14f98f6f0feb951}, -- {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3}, -- {0xc3b8358109e84f07, 0x0a862f80ec4700c8}, -- {0xf4a642e14c6262c8, 0xcd27bb612758c0fa}, -- {0x98e7e9cccfbd7dbd, 0x8038d51cb897789c}, -- {0xbf21e44003acdd2c, 0xe0470a63e6bd56c3}, -- {0xeeea5d5004981478, 0x1858ccfce06cac74}, -- {0x95527a5202df0ccb, 0x0f37801e0c43ebc8}, -- {0xbaa718e68396cffd, 0xd30560258f54e6ba}, -- {0xe950df20247c83fd, 0x47c6b82ef32a2069}, -- {0x91d28b7416cdd27e, 0x4cdc331d57fa5441}, -- {0xb6472e511c81471d, 0xe0133fe4adf8e952}, -- {0xe3d8f9e563a198e5, 0x58180fddd97723a6}, -- {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648}, -- {0xb201833b35d63f73, 0x2cd2cc6551e513da}, -- {0xde81e40a034bcf4f, 0xf8077f7ea65e58d1}, -- {0x8b112e86420f6191, 0xfb04afaf27faf782}, -- {0xadd57a27d29339f6, 0x79c5db9af1f9b563}, -- {0xd94ad8b1c7380874, 0x18375281ae7822bc}, -- {0x87cec76f1c830548, 0x8f2293910d0b15b5}, -- {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb22}, -- {0xd433179d9c8cb841, 0x5fa60692a46151eb}, -- {0x849feec281d7f328, 0xdbc7c41ba6bcd333}, -- {0xa5c7ea73224deff3, 0x12b9b522906c0800}, -- {0xcf39e50feae16bef, 0xd768226b34870a00}, -- {0x81842f29f2cce375, 0xe6a1158300d46640}, -- {0xa1e53af46f801c53, 0x60495ae3c1097fd0}, -- {0xca5e89b18b602368, 0x385bb19cb14bdfc4}, -- {0xfcf62c1dee382c42, 0x46729e03dd9ed7b5}, -- {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d1}, -- {0xc5a05277621be293, 0xc7098b7305241885}, -- {0xf70867153aa2db38, 0xb8cbee4fc66d1ea7} --#else -- {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, -- {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, -- {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, -- {0x86a8d39ef77164bc, 0xae5dff9c02033198}, -- {0xd98ddaee19068c76, 0x3badd624dd9b0958}, -- {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, -- {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, -- {0xe55990879ddcaabd, 0xcc420a6a101d0516}, -- {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, -- {0x95a8637627989aad, 0xdde7001379a44aa9}, -- {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, -- {0xc350000000000000, 0x0000000000000000}, -- {0x9dc5ada82b70b59d, 0xf020000000000000}, -- {0xfee50b7025c36a08, 0x02f236d04753d5b4}, -- {0xcde6fd5e09abcf26, 0xed4c0226b55e6f86}, -- {0xa6539930bf6bff45, 0x84db8346b786151c}, -- {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b2}, -- {0xd910f7ff28069da4, 0x1b2ba1518094da04}, -- {0xaf58416654a6babb, 0x387ac8d1970027b2}, -- {0x8da471a9de737e24, 0x5ceaecfed289e5d2}, -- {0xe4d5e82392a40515, 0x0fabaf3feaa5334a}, -- {0xb8da1662e7b00a17, 0x3d6a751f3b936243}, -- {0x95527a5202df0ccb, 0x0f37801e0c43ebc8} --#endif --}; -- --#if !FMT_USE_FULL_CACHE_DRAGONBOX --template <typename T> --const uint64_t basic_data<T>::powers_of_5_64[] = { -- 0x0000000000000001, 0x0000000000000005, 0x0000000000000019, -- 0x000000000000007d, 0x0000000000000271, 0x0000000000000c35, -- 0x0000000000003d09, 0x000000000001312d, 0x000000000005f5e1, -- 0x00000000001dcd65, 0x00000000009502f9, 0x0000000002e90edd, -- 0x000000000e8d4a51, 0x0000000048c27395, 0x000000016bcc41e9, -- 0x000000071afd498d, 0x0000002386f26fc1, 0x000000b1a2bc2ec5, -- 0x000003782dace9d9, 0x00001158e460913d, 0x000056bc75e2d631, -- 0x0001b1ae4d6e2ef5, 0x000878678326eac9, 0x002a5a058fc295ed, -- 0x00d3c21bcecceda1, 0x0422ca8b0a00a425, 0x14adf4b7320334b9}; -- --template <typename T> --const uint32_t basic_data<T>::dragonbox_pow10_recovery_errors[] = { -- 0x50001400, 0x54044100, 0x54014555, 0x55954415, 0x54115555, 0x00000001, -- 0x50000000, 0x00104000, 0x54010004, 0x05004001, 0x55555544, 0x41545555, -- 0x54040551, 0x15445545, 0x51555514, 0x10000015, 0x00101100, 0x01100015, -- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04450514, 0x45414110, -- 0x55555145, 0x50544050, 0x15040155, 0x11054140, 0x50111514, 0x11451454, -- 0x00400541, 0x00000000, 0x55555450, 0x10056551, 0x10054011, 0x55551014, -- 0x69514555, 0x05151109, 0x00155555}; -+constexpr const char basic_data<T>::right_padding_shifts[]; - #endif - --template <typename T> --const char basic_data<T>::foreground_color[] = "\x1b[38;2;"; --template <typename T> --const char basic_data<T>::background_color[] = "\x1b[48;2;"; --template <typename T> const char basic_data<T>::reset_color[] = "\x1b[0m"; --template <typename T> const wchar_t basic_data<T>::wreset_color[] = L"\x1b[0m"; --template <typename T> const char basic_data<T>::signs[] = {0, '-', '+', ' '}; --template <typename T> --const char basic_data<T>::left_padding_shifts[] = {31, 31, 0, 1, 0}; --template <typename T> --const char basic_data<T>::right_padding_shifts[] = {0, 31, 0, 1, 0}; -- - template <typename T> struct bits { - static FMT_CONSTEXPR_DECL const int value = - static_cast<int>(sizeof(T) * std::numeric_limits<unsigned char>::digits); -@@ -1197,6 +277,52 @@ inline fp operator*(fp x, fp y) { return {multiply(x.f, y.f), x.e + y.e + 64}; } - // Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its - // (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`. - inline fp get_cached_power(int min_exponent, int& pow10_exponent) { -+ // Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. -+ // These are generated by support/compute-powers.py. -+ static constexpr const uint64_t pow10_significands[] = { -+ 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, -+ 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, -+ 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, -+ 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, -+ 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, -+ 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7, -+ 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e, -+ 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, -+ 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, -+ 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, -+ 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f, -+ 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, -+ 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, -+ 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, -+ 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000, -+ 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984, -+ 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, -+ 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, -+ 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758, -+ 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85, -+ 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, -+ 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25, -+ 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2, -+ 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a, -+ 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, -+ 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129, -+ 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85, -+ 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, -+ 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, -+ }; -+ -+ // Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding -+ // to significands above. -+ static constexpr const int16_t pow10_exponents[] = { -+ -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -+ -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, -+ -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, -+ -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, -+ -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, -+ 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, -+ 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, -+ 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066}; -+ - const int shift = 32; - const auto significand = static_cast<int64_t>(data::log10_2_significand); - int index = static_cast<int>( -@@ -1210,8 +336,7 @@ inline fp get_cached_power(int min_exponent, int& pow10_exponent) { - const int dec_exp_step = 8; - index = (index - first_dec_exp - 1) / dec_exp_step + 1; - pow10_exponent = first_dec_exp + index * dec_exp_step; -- return {data::grisu_pow10_significands[index], -- data::grisu_pow10_exponents[index]}; -+ return {pow10_significands[index], pow10_exponents[index]}; - } - - // A simple accumulator to hold the sums of terms in bigint::square if uint128_t -@@ -1228,7 +353,7 @@ struct accumulator { - if (lower < n) ++upper; - } - void operator>>=(int shift) { -- assert(shift == 32); -+ FMT_ASSERT(shift == 32, ""); - (void)shift; - lower = (upper << 32) | (lower >> 32); - upper >>= 32; -@@ -1307,7 +432,7 @@ class bigint { - public: - bigint() : exp_(0) {} - explicit bigint(uint64_t n) { assign(n); } -- ~bigint() { assert(bigits_.capacity() <= bigits_capacity); } -+ ~bigint() { FMT_ASSERT(bigits_.capacity() <= bigits_capacity, ""); } - - bigint(const bigint&) = delete; - void operator=(const bigint&) = delete; -@@ -1333,7 +458,7 @@ class bigint { - int num_bigits() const { return static_cast<int>(bigits_.size()) + exp_; } - - FMT_NOINLINE bigint& operator<<=(int shift) { -- assert(shift >= 0); -+ FMT_ASSERT(shift >= 0, ""); - exp_ += shift / bigit_bits; - shift %= bigit_bits; - if (shift == 0) return *this; -@@ -1395,7 +520,7 @@ class bigint { - - // Assigns pow(10, exp) to this bigint. - void assign_pow10(int exp) { -- assert(exp >= 0); -+ FMT_ASSERT(exp >= 0, ""); - if (exp == 0) return assign(1); - // Find the top bit. - int bitmask = 1; -@@ -1414,9 +539,9 @@ class bigint { - } - - void square() { -- basic_memory_buffer<bigit, bigits_capacity> n(std::move(bigits_)); - int num_bigits = static_cast<int>(bigits_.size()); - int num_result_bigits = 2 * num_bigits; -+ basic_memory_buffer<bigit, bigits_capacity> n(std::move(bigits_)); - bigits_.resize(to_unsigned(num_result_bigits)); - using accumulator_t = conditional_t<FMT_USE_INT128, uint128_t, accumulator>; - auto sum = accumulator_t(); -@@ -1502,12 +627,19 @@ enum result { - }; - } - -+inline uint64_t power_of_10_64(int exp) { -+ static constexpr const uint64_t data[] = {1, FMT_POWERS_OF_10(1), -+ FMT_POWERS_OF_10(1000000000ULL), -+ 10000000000000000000ULL}; -+ return data[exp]; -+} -+ - // 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> --FMT_ALWAYS_INLINE digits::result grisu_gen_digits(fp value, uint64_t error, -- int& exp, Handler& handler) { -+FMT_INLINE digits::result grisu_gen_digits(fp value, uint64_t error, int& exp, -+ Handler& handler) { - const 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 -@@ -1519,7 +651,7 @@ FMT_ALWAYS_INLINE digits::result grisu_gen_digits(fp value, uint64_t error, - uint64_t fractional = value.f & (one.f - 1); - exp = count_digits(integral); // kappa in Grisu. - // Divide by 10 to prevent overflow. -- auto result = handler.on_start(data::powers_of_10_64[exp - 1] << -one.e, -+ auto result = handler.on_start(power_of_10_64(exp - 1) << -one.e, - value.f / 10, error * 10, exp); - if (result != digits::more) return result; - // Generate digits for the integral part. This can produce up to 10 digits. -@@ -1569,8 +701,8 @@ FMT_ALWAYS_INLINE digits::result grisu_gen_digits(fp value, uint64_t error, - --exp; - auto remainder = (static_cast<uint64_t>(integral) << -one.e) + fractional; - result = handler.on_digit(static_cast<char>('0' + digit), -- data::powers_of_10_64[exp] << -one.e, remainder, -- error, exp, true); -+ power_of_10_64(exp) << -one.e, remainder, error, -+ exp, true); - if (result != digits::more) return result; - } while (exp > 0); - // Generate digits for the fractional part. -@@ -1643,11 +775,58 @@ struct fixed_handler { - } - }; - -+// A 128-bit integer type used internally, -+struct uint128_wrapper { -+ uint128_wrapper() = default; -+ -+#if FMT_USE_INT128 -+ uint128_t internal_; -+ -+ constexpr uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT -+ : internal_{static_cast<uint128_t>(low) | -+ (static_cast<uint128_t>(high) << 64)} {} -+ -+ constexpr uint128_wrapper(uint128_t u) : internal_{u} {} -+ -+ constexpr uint64_t high() const FMT_NOEXCEPT { -+ return uint64_t(internal_ >> 64); -+ } -+ constexpr uint64_t low() const FMT_NOEXCEPT { return uint64_t(internal_); } -+ -+ uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT { -+ internal_ += n; -+ return *this; -+ } -+#else -+ uint64_t high_; -+ uint64_t low_; -+ -+ constexpr uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT -+ : high_{high}, -+ low_{low} {} -+ -+ constexpr uint64_t high() const FMT_NOEXCEPT { return high_; } -+ constexpr uint64_t low() const FMT_NOEXCEPT { return low_; } -+ -+ uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT { -+# if defined(_MSC_VER) && defined(_M_X64) -+ unsigned char carry = _addcarry_u64(0, low_, n, &low_); -+ _addcarry_u64(carry, high_, 0, &high_); -+ return *this; -+# else -+ uint64_t sum = low_ + n; -+ high_ += (sum < low_ ? 1 : 0); -+ low_ = sum; -+ return *this; -+# endif -+ } -+#endif -+}; -+ - // Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox. - namespace dragonbox { - // Computes 128-bit result of multiplication of two 64-bit unsigned integers. --FMT_SAFEBUFFERS inline uint128_wrapper umul128(uint64_t x, -- uint64_t y) FMT_NOEXCEPT { -+inline uint128_wrapper umul128(uint64_t x, uint64_t y) FMT_NOEXCEPT { - #if FMT_USE_INT128 - return static_cast<uint128_t>(x) * static_cast<uint128_t>(y); - #elif defined(_MSC_VER) && defined(_M_X64) -@@ -1675,8 +854,7 @@ FMT_SAFEBUFFERS inline uint128_wrapper umul128(uint64_t x, - } - - // Computes upper 64 bits of multiplication of two 64-bit unsigned integers. --FMT_SAFEBUFFERS inline uint64_t umul128_upper64(uint64_t x, -- uint64_t y) FMT_NOEXCEPT { -+inline uint64_t umul128_upper64(uint64_t x, uint64_t y) FMT_NOEXCEPT { - #if FMT_USE_INT128 - auto p = static_cast<uint128_t>(x) * static_cast<uint128_t>(y); - return static_cast<uint64_t>(p >> 64); -@@ -1689,8 +867,7 @@ FMT_SAFEBUFFERS inline uint64_t umul128_upper64(uint64_t x, - - // Computes upper 64 bits of multiplication of a 64-bit unsigned integer and a - // 128-bit unsigned integer. --FMT_SAFEBUFFERS inline uint64_t umul192_upper64(uint64_t x, uint128_wrapper y) -- FMT_NOEXCEPT { -+inline uint64_t umul192_upper64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT { - uint128_wrapper g0 = umul128(x, y.high()); - g0 += umul128_upper64(x, y.low()); - return g0.high(); -@@ -1704,8 +881,7 @@ inline uint32_t umul96_upper32(uint32_t x, uint64_t y) FMT_NOEXCEPT { - - // Computes middle 64 bits of multiplication of a 64-bit unsigned integer and a - // 128-bit unsigned integer. --FMT_SAFEBUFFERS inline uint64_t umul192_middle64(uint64_t x, uint128_wrapper y) -- FMT_NOEXCEPT { -+inline uint64_t umul192_middle64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT { - uint64_t g01 = x * y.high(); - uint64_t g10 = umul128_upper64(x, y.low()); - return g01 + g10; -@@ -1768,16 +944,52 @@ inline bool divisible_by_power_of_2(uint64_t x, int exp) FMT_NOEXCEPT { - #endif - } - -+// Table entry type for divisibility test. -+template <typename T> struct divtest_table_entry { -+ T mod_inv; -+ T max_quotient; -+}; -+ - // Returns true iff x is divisible by pow(5, exp). - inline bool divisible_by_power_of_5(uint32_t x, int exp) FMT_NOEXCEPT { - FMT_ASSERT(exp <= 10, "too large exponent"); -- return x * data::divtest_table_for_pow5_32[exp].mod_inv <= -- data::divtest_table_for_pow5_32[exp].max_quotient; -+ static constexpr const divtest_table_entry<uint32_t> divtest_table[] = { -+ {0x00000001, 0xffffffff}, {0xcccccccd, 0x33333333}, -+ {0xc28f5c29, 0x0a3d70a3}, {0x26e978d5, 0x020c49ba}, -+ {0x3afb7e91, 0x0068db8b}, {0x0bcbe61d, 0x0014f8b5}, -+ {0x68c26139, 0x000431bd}, {0xae8d46a5, 0x0000d6bf}, -+ {0x22e90e21, 0x00002af3}, {0x3a2e9c6d, 0x00000897}, -+ {0x3ed61f49, 0x000001b7}}; -+ return x * divtest_table[exp].mod_inv <= divtest_table[exp].max_quotient; - } - inline bool divisible_by_power_of_5(uint64_t x, int exp) FMT_NOEXCEPT { - FMT_ASSERT(exp <= 23, "too large exponent"); -- return x * data::divtest_table_for_pow5_64[exp].mod_inv <= -- data::divtest_table_for_pow5_64[exp].max_quotient; -+ static constexpr const divtest_table_entry<uint64_t> divtest_table[] = { -+ {0x0000000000000001, 0xffffffffffffffff}, -+ {0xcccccccccccccccd, 0x3333333333333333}, -+ {0x8f5c28f5c28f5c29, 0x0a3d70a3d70a3d70}, -+ {0x1cac083126e978d5, 0x020c49ba5e353f7c}, -+ {0xd288ce703afb7e91, 0x0068db8bac710cb2}, -+ {0x5d4e8fb00bcbe61d, 0x0014f8b588e368f0}, -+ {0x790fb65668c26139, 0x000431bde82d7b63}, -+ {0xe5032477ae8d46a5, 0x0000d6bf94d5e57a}, -+ {0xc767074b22e90e21, 0x00002af31dc46118}, -+ {0x8e47ce423a2e9c6d, 0x0000089705f4136b}, -+ {0x4fa7f60d3ed61f49, 0x000001b7cdfd9d7b}, -+ {0x0fee64690c913975, 0x00000057f5ff85e5}, -+ {0x3662e0e1cf503eb1, 0x000000119799812d}, -+ {0xa47a2cf9f6433fbd, 0x0000000384b84d09}, -+ {0x54186f653140a659, 0x00000000b424dc35}, -+ {0x7738164770402145, 0x0000000024075f3d}, -+ {0xe4a4d1417cd9a041, 0x000000000734aca5}, -+ {0xc75429d9e5c5200d, 0x000000000170ef54}, -+ {0xc1773b91fac10669, 0x000000000049c977}, -+ {0x26b172506559ce15, 0x00000000000ec1e4}, -+ {0xd489e3a9addec2d1, 0x000000000002f394}, -+ {0x90e860bb892c8d5d, 0x000000000000971d}, -+ {0x502e79bf1b6f4f79, 0x0000000000001e39}, -+ {0xdcd618596be30fe5, 0x000000000000060b}}; -+ return x * divtest_table[exp].mod_inv <= divtest_table[exp].max_quotient; - } - - // Replaces n by floor(n / pow(5, N)) returning true if and only if n is -@@ -1831,7 +1043,34 @@ template <> struct cache_accessor<float> { - static uint64_t get_cached_power(int k) FMT_NOEXCEPT { - FMT_ASSERT(k >= float_info<float>::min_k && k <= float_info<float>::max_k, - "k is out of range"); -- return data::dragonbox_pow10_significands_64[k - float_info<float>::min_k]; -+ constexpr const uint64_t pow10_significands[] = { -+ 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f, -+ 0xfd87b5f28300ca0e, 0x9e74d1b791e07e49, 0xc612062576589ddb, -+ 0xf79687aed3eec552, 0x9abe14cd44753b53, 0xc16d9a0095928a28, -+ 0xf1c90080baf72cb2, 0x971da05074da7bef, 0xbce5086492111aeb, -+ 0xec1e4a7db69561a6, 0x9392ee8e921d5d08, 0xb877aa3236a4b44a, -+ 0xe69594bec44de15c, 0x901d7cf73ab0acda, 0xb424dc35095cd810, -+ 0xe12e13424bb40e14, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff, -+ 0xdbe6fecebdedd5bf, 0x89705f4136b4a598, 0xabcc77118461cefd, -+ 0xd6bf94d5e57a42bd, 0x8637bd05af6c69b6, 0xa7c5ac471b478424, -+ 0xd1b71758e219652c, 0x83126e978d4fdf3c, 0xa3d70a3d70a3d70b, -+ 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000, -+ 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000, -+ 0xc350000000000000, 0xf424000000000000, 0x9896800000000000, -+ 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000, -+ 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000, -+ 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000, -+ 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, -+ 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000, -+ 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0, -+ 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940984, -+ 0xa18f07d736b90be5, 0xc9f2c9cd04674ede, 0xfc6f7c4045812296, -+ 0x9dc5ada82b70b59d, 0xc5371912364ce305, 0xf684df56c3e01bc6, -+ 0x9a130b963a6c115c, 0xc097ce7bc90715b3, 0xf0bdc21abb48db20, -+ 0x96769950b50d88f4, 0xbc143fa4e250eb31, 0xeb194f8e1ae525fd, -+ 0x92efd1b8d0cf37be, 0xb7abc627050305ad, 0xe596b7b0c643c719, -+ 0x8f7e32ce7bea5c6f, 0xb35dbf821ae4f38b, 0xe0352f62a19e306e}; -+ return pow10_significands[k - float_info<float>::min_k]; - } - - static carrier_uint compute_mul(carrier_uint u, -@@ -1885,10 +1124,679 @@ template <> struct cache_accessor<double> { - FMT_ASSERT(k >= float_info<double>::min_k && k <= float_info<double>::max_k, - "k is out of range"); - -+ static constexpr const uint128_wrapper pow10_significands[] = { - #if FMT_USE_FULL_CACHE_DRAGONBOX -- return data::dragonbox_pow10_significands_128[k - -- float_info<double>::min_k]; -+ {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, -+ {0x9faacf3df73609b1, 0x77b191618c54e9ad}, -+ {0xc795830d75038c1d, 0xd59df5b9ef6a2418}, -+ {0xf97ae3d0d2446f25, 0x4b0573286b44ad1e}, -+ {0x9becce62836ac577, 0x4ee367f9430aec33}, -+ {0xc2e801fb244576d5, 0x229c41f793cda740}, -+ {0xf3a20279ed56d48a, 0x6b43527578c11110}, -+ {0x9845418c345644d6, 0x830a13896b78aaaa}, -+ {0xbe5691ef416bd60c, 0x23cc986bc656d554}, -+ {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9}, -+ {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa}, -+ {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54}, -+ {0xe858ad248f5c22c9, 0xd1b3400f8f9cff69}, -+ {0x91376c36d99995be, 0x23100809b9c21fa2}, -+ {0xb58547448ffffb2d, 0xabd40a0c2832a78b}, -+ {0xe2e69915b3fff9f9, 0x16c90c8f323f516d}, -+ {0x8dd01fad907ffc3b, 0xae3da7d97f6792e4}, -+ {0xb1442798f49ffb4a, 0x99cd11cfdf41779d}, -+ {0xdd95317f31c7fa1d, 0x40405643d711d584}, -+ {0x8a7d3eef7f1cfc52, 0x482835ea666b2573}, -+ {0xad1c8eab5ee43b66, 0xda3243650005eed0}, -+ {0xd863b256369d4a40, 0x90bed43e40076a83}, -+ {0x873e4f75e2224e68, 0x5a7744a6e804a292}, -+ {0xa90de3535aaae202, 0x711515d0a205cb37}, -+ {0xd3515c2831559a83, 0x0d5a5b44ca873e04}, -+ {0x8412d9991ed58091, 0xe858790afe9486c3}, -+ {0xa5178fff668ae0b6, 0x626e974dbe39a873}, -+ {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, -+ {0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a}, -+ {0xa139029f6a239f72, 0x1c1fffc1ebc44e81}, -+ {0xc987434744ac874e, 0xa327ffb266b56221}, -+ {0xfbe9141915d7a922, 0x4bf1ff9f0062baa9}, -+ {0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa}, -+ {0xc4ce17b399107c22, 0xcb550fb4384d21d4}, -+ {0xf6019da07f549b2b, 0x7e2a53a146606a49}, -+ {0x99c102844f94e0fb, 0x2eda7444cbfc426e}, -+ {0xc0314325637a1939, 0xfa911155fefb5309}, -+ {0xf03d93eebc589f88, 0x793555ab7eba27cb}, -+ {0x96267c7535b763b5, 0x4bc1558b2f3458df}, -+ {0xbbb01b9283253ca2, 0x9eb1aaedfb016f17}, -+ {0xea9c227723ee8bcb, 0x465e15a979c1cadd}, -+ {0x92a1958a7675175f, 0x0bfacd89ec191eca}, -+ {0xb749faed14125d36, 0xcef980ec671f667c}, -+ {0xe51c79a85916f484, 0x82b7e12780e7401b}, -+ {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811}, -+ {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16}, -+ {0xdfbdcece67006ac9, 0x67a791e093e1d49b}, -+ {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1}, -+ {0xaecc49914078536d, 0x58fae9f773886e19}, -+ {0xda7f5bf590966848, 0xaf39a475506a899f}, -+ {0x888f99797a5e012d, 0x6d8406c952429604}, -+ {0xaab37fd7d8f58178, 0xc8e5087ba6d33b84}, -+ {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65}, -+ {0x855c3be0a17fcd26, 0x5cf2eea09a550680}, -+ {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, -+ {0xd0601d8efc57b08b, 0xf13b94daf124da27}, -+ {0x823c12795db6ce57, 0x76c53d08d6b70859}, -+ {0xa2cb1717b52481ed, 0x54768c4b0c64ca6f}, -+ {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a}, -+ {0xfe5d54150b090b02, 0xd3f93b35435d7c4d}, -+ {0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0}, -+ {0xc6b8e9b0709f109a, 0x359ab6419ca1091c}, -+ {0xf867241c8cc6d4c0, 0xc30163d203c94b63}, -+ {0x9b407691d7fc44f8, 0x79e0de63425dcf1e}, -+ {0xc21094364dfb5636, 0x985915fc12f542e5}, -+ {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e}, -+ {0x979cf3ca6cec5b5a, 0xa705992ceecf9c43}, -+ {0xbd8430bd08277231, 0x50c6ff782a838354}, -+ {0xece53cec4a314ebd, 0xa4f8bf5635246429}, -+ {0x940f4613ae5ed136, 0x871b7795e136be9a}, -+ {0xb913179899f68584, 0x28e2557b59846e40}, -+ {0xe757dd7ec07426e5, 0x331aeada2fe589d0}, -+ {0x9096ea6f3848984f, 0x3ff0d2c85def7622}, -+ {0xb4bca50b065abe63, 0x0fed077a756b53aa}, -+ {0xe1ebce4dc7f16dfb, 0xd3e8495912c62895}, -+ {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d}, -+ {0xb080392cc4349dec, 0xbd8d794d96aacfb4}, -+ {0xdca04777f541c567, 0xecf0d7a0fc5583a1}, -+ {0x89e42caaf9491b60, 0xf41686c49db57245}, -+ {0xac5d37d5b79b6239, 0x311c2875c522ced6}, -+ {0xd77485cb25823ac7, 0x7d633293366b828c}, -+ {0x86a8d39ef77164bc, 0xae5dff9c02033198}, -+ {0xa8530886b54dbdeb, 0xd9f57f830283fdfd}, -+ {0xd267caa862a12d66, 0xd072df63c324fd7c}, -+ {0x8380dea93da4bc60, 0x4247cb9e59f71e6e}, -+ {0xa46116538d0deb78, 0x52d9be85f074e609}, -+ {0xcd795be870516656, 0x67902e276c921f8c}, -+ {0x806bd9714632dff6, 0x00ba1cd8a3db53b7}, -+ {0xa086cfcd97bf97f3, 0x80e8a40eccd228a5}, -+ {0xc8a883c0fdaf7df0, 0x6122cd128006b2ce}, -+ {0xfad2a4b13d1b5d6c, 0x796b805720085f82}, -+ {0x9cc3a6eec6311a63, 0xcbe3303674053bb1}, -+ {0xc3f490aa77bd60fc, 0xbedbfc4411068a9d}, -+ {0xf4f1b4d515acb93b, 0xee92fb5515482d45}, -+ {0x991711052d8bf3c5, 0x751bdd152d4d1c4b}, -+ {0xbf5cd54678eef0b6, 0xd262d45a78a0635e}, -+ {0xef340a98172aace4, 0x86fb897116c87c35}, -+ {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1}, -+ {0xbae0a846d2195712, 0x8974836059cca10a}, -+ {0xe998d258869facd7, 0x2bd1a438703fc94c}, -+ {0x91ff83775423cc06, 0x7b6306a34627ddd0}, -+ {0xb67f6455292cbf08, 0x1a3bc84c17b1d543}, -+ {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94}, -+ {0x8e938662882af53e, 0x547eb47b7282ee9d}, -+ {0xb23867fb2a35b28d, 0xe99e619a4f23aa44}, -+ {0xdec681f9f4c31f31, 0x6405fa00e2ec94d5}, -+ {0x8b3c113c38f9f37e, 0xde83bc408dd3dd05}, -+ {0xae0b158b4738705e, 0x9624ab50b148d446}, -+ {0xd98ddaee19068c76, 0x3badd624dd9b0958}, -+ {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7}, -+ {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d}, -+ {0xd47487cc8470652b, 0x7647c32000696720}, -+ {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074}, -+ {0xa5fb0a17c777cf09, 0xf468107100525891}, -+ {0xcf79cc9db955c2cc, 0x7182148d4066eeb5}, -+ {0x81ac1fe293d599bf, 0xc6f14cd848405531}, -+ {0xa21727db38cb002f, 0xb8ada00e5a506a7d}, -+ {0xca9cf1d206fdc03b, 0xa6d90811f0e4851d}, -+ {0xfd442e4688bd304a, 0x908f4a166d1da664}, -+ {0x9e4a9cec15763e2e, 0x9a598e4e043287ff}, -+ {0xc5dd44271ad3cdba, 0x40eff1e1853f29fe}, -+ {0xf7549530e188c128, 0xd12bee59e68ef47d}, -+ {0x9a94dd3e8cf578b9, 0x82bb74f8301958cf}, -+ {0xc13a148e3032d6e7, 0xe36a52363c1faf02}, -+ {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2}, -+ {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba}, -+ {0xbcb2b812db11a5de, 0x7415d448f6b6f0e8}, -+ {0xebdf661791d60f56, 0x111b495b3464ad22}, -+ {0x936b9fcebb25c995, 0xcab10dd900beec35}, -+ {0xb84687c269ef3bfb, 0x3d5d514f40eea743}, -+ {0xe65829b3046b0afa, 0x0cb4a5a3112a5113}, -+ {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac}, -+ {0xb3f4e093db73a093, 0x59ed216765690f57}, -+ {0xe0f218b8d25088b8, 0x306869c13ec3532d}, -+ {0x8c974f7383725573, 0x1e414218c73a13fc}, -+ {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, -+ {0xdbac6c247d62a583, 0xdf45f746b74abf3a}, -+ {0x894bc396ce5da772, 0x6b8bba8c328eb784}, -+ {0xab9eb47c81f5114f, 0x066ea92f3f326565}, -+ {0xd686619ba27255a2, 0xc80a537b0efefebe}, -+ {0x8613fd0145877585, 0xbd06742ce95f5f37}, -+ {0xa798fc4196e952e7, 0x2c48113823b73705}, -+ {0xd17f3b51fca3a7a0, 0xf75a15862ca504c6}, -+ {0x82ef85133de648c4, 0x9a984d73dbe722fc}, -+ {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb}, -+ {0xcc963fee10b7d1b3, 0x318df905079926a9}, -+ {0xffbbcfe994e5c61f, 0xfdf17746497f7053}, -+ {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634}, -+ {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1}, -+ {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1}, -+ {0x9c1661a651213e2d, 0x06bea10ca65c084f}, -+ {0xc31bfa0fe5698db8, 0x486e494fcff30a63}, -+ {0xf3e2f893dec3f126, 0x5a89dba3c3efccfb}, -+ {0x986ddb5c6b3a76b7, 0xf89629465a75e01d}, -+ {0xbe89523386091465, 0xf6bbb397f1135824}, -+ {0xee2ba6c0678b597f, 0x746aa07ded582e2d}, -+ {0x94db483840b717ef, 0xa8c2a44eb4571cdd}, -+ {0xba121a4650e4ddeb, 0x92f34d62616ce414}, -+ {0xe896a0d7e51e1566, 0x77b020baf9c81d18}, -+ {0x915e2486ef32cd60, 0x0ace1474dc1d122f}, -+ {0xb5b5ada8aaff80b8, 0x0d819992132456bb}, -+ {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a}, -+ {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, -+ {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3}, -+ {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf}, -+ {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c}, -+ {0xad4ab7112eb3929d, 0x86c16c98d2c953c7}, -+ {0xd89d64d57a607744, 0xe871c7bf077ba8b8}, -+ {0x87625f056c7c4a8b, 0x11471cd764ad4973}, -+ {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0}, -+ {0xd389b47879823479, 0x4aff1d108d4ec2c4}, -+ {0x843610cb4bf160cb, 0xcedf722a585139bb}, -+ {0xa54394fe1eedb8fe, 0xc2974eb4ee658829}, -+ {0xce947a3da6a9273e, 0x733d226229feea33}, -+ {0x811ccc668829b887, 0x0806357d5a3f5260}, -+ {0xa163ff802a3426a8, 0xca07c2dcb0cf26f8}, -+ {0xc9bcff6034c13052, 0xfc89b393dd02f0b6}, -+ {0xfc2c3f3841f17c67, 0xbbac2078d443ace3}, -+ {0x9d9ba7832936edc0, 0xd54b944b84aa4c0e}, -+ {0xc5029163f384a931, 0x0a9e795e65d4df12}, -+ {0xf64335bcf065d37d, 0x4d4617b5ff4a16d6}, -+ {0x99ea0196163fa42e, 0x504bced1bf8e4e46}, -+ {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7}, -+ {0xf07da27a82c37088, 0x5d767327bb4e5a4d}, -+ {0x964e858c91ba2655, 0x3a6a07f8d510f870}, -+ {0xbbe226efb628afea, 0x890489f70a55368c}, -+ {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f}, -+ {0x92c8ae6b464fc96f, 0x3b0b8bc90012929e}, -+ {0xb77ada0617e3bbcb, 0x09ce6ebb40173745}, -+ {0xe55990879ddcaabd, 0xcc420a6a101d0516}, -+ {0x8f57fa54c2a9eab6, 0x9fa946824a12232e}, -+ {0xb32df8e9f3546564, 0x47939822dc96abfa}, -+ {0xdff9772470297ebd, 0x59787e2b93bc56f8}, -+ {0x8bfbea76c619ef36, 0x57eb4edb3c55b65b}, -+ {0xaefae51477a06b03, 0xede622920b6b23f2}, -+ {0xdab99e59958885c4, 0xe95fab368e45ecee}, -+ {0x88b402f7fd75539b, 0x11dbcb0218ebb415}, -+ {0xaae103b5fcd2a881, 0xd652bdc29f26a11a}, -+ {0xd59944a37c0752a2, 0x4be76d3346f04960}, -+ {0x857fcae62d8493a5, 0x6f70a4400c562ddc}, -+ {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953}, -+ {0xd097ad07a71f26b2, 0x7e2000a41346a7a8}, -+ {0x825ecc24c873782f, 0x8ed400668c0c28c9}, -+ {0xa2f67f2dfa90563b, 0x728900802f0f32fb}, -+ {0xcbb41ef979346bca, 0x4f2b40a03ad2ffba}, -+ {0xfea126b7d78186bc, 0xe2f610c84987bfa9}, -+ {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca}, -+ {0xc6ede63fa05d3143, 0x91503d1c79720dbc}, -+ {0xf8a95fcf88747d94, 0x75a44c6397ce912b}, -+ {0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb}, -+ {0xc24452da229b021b, 0xfbe85badce996169}, -+ {0xf2d56790ab41c2a2, 0xfae27299423fb9c4}, -+ {0x97c560ba6b0919a5, 0xdccd879fc967d41b}, -+ {0xbdb6b8e905cb600f, 0x5400e987bbc1c921}, -+ {0xed246723473e3813, 0x290123e9aab23b69}, -+ {0x9436c0760c86e30b, 0xf9a0b6720aaf6522}, -+ {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, -+ {0xe7958cb87392c2c2, 0xb60b1d1230b20e05}, -+ {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3}, -+ {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4}, -+ {0xe2280b6c20dd5232, 0x25c6da63c38de1b1}, -+ {0x8d590723948a535f, 0x579c487e5a38ad0f}, -+ {0xb0af48ec79ace837, 0x2d835a9df0c6d852}, -+ {0xdcdb1b2798182244, 0xf8e431456cf88e66}, -+ {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900}, -+ {0xac8b2d36eed2dac5, 0xe272467e3d222f40}, -+ {0xd7adf884aa879177, 0x5b0ed81dcc6abb10}, -+ {0x86ccbb52ea94baea, 0x98e947129fc2b4ea}, -+ {0xa87fea27a539e9a5, 0x3f2398d747b36225}, -+ {0xd29fe4b18e88640e, 0x8eec7f0d19a03aae}, -+ {0x83a3eeeef9153e89, 0x1953cf68300424ad}, -+ {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8}, -+ {0xcdb02555653131b6, 0x3792f412cb06794e}, -+ {0x808e17555f3ebf11, 0xe2bbd88bbee40bd1}, -+ {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5}, -+ {0xc8de047564d20a8b, 0xf245825a5a445276}, -+ {0xfb158592be068d2e, 0xeed6e2f0f0d56713}, -+ {0x9ced737bb6c4183d, 0x55464dd69685606c}, -+ {0xc428d05aa4751e4c, 0xaa97e14c3c26b887}, -+ {0xf53304714d9265df, 0xd53dd99f4b3066a9}, -+ {0x993fe2c6d07b7fab, 0xe546a8038efe402a}, -+ {0xbf8fdb78849a5f96, 0xde98520472bdd034}, -+ {0xef73d256a5c0f77c, 0x963e66858f6d4441}, -+ {0x95a8637627989aad, 0xdde7001379a44aa9}, -+ {0xbb127c53b17ec159, 0x5560c018580d5d53}, -+ {0xe9d71b689dde71af, 0xaab8f01e6e10b4a7}, -+ {0x9226712162ab070d, 0xcab3961304ca70e9}, -+ {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23}, -+ {0xe45c10c42a2b3b05, 0x8cb89a7db77c506b}, -+ {0x8eb98a7a9a5b04e3, 0x77f3608e92adb243}, -+ {0xb267ed1940f1c61c, 0x55f038b237591ed4}, -+ {0xdf01e85f912e37a3, 0x6b6c46dec52f6689}, -+ {0x8b61313bbabce2c6, 0x2323ac4b3b3da016}, -+ {0xae397d8aa96c1b77, 0xabec975e0a0d081b}, -+ {0xd9c7dced53c72255, 0x96e7bd358c904a22}, -+ {0x881cea14545c7575, 0x7e50d64177da2e55}, -+ {0xaa242499697392d2, 0xdde50bd1d5d0b9ea}, -+ {0xd4ad2dbfc3d07787, 0x955e4ec64b44e865}, -+ {0x84ec3c97da624ab4, 0xbd5af13bef0b113f}, -+ {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f}, -+ {0xcfb11ead453994ba, 0x67de18eda5814af3}, -+ {0x81ceb32c4b43fcf4, 0x80eacf948770ced8}, -+ {0xa2425ff75e14fc31, 0xa1258379a94d028e}, -+ {0xcad2f7f5359a3b3e, 0x096ee45813a04331}, -+ {0xfd87b5f28300ca0d, 0x8bca9d6e188853fd}, -+ {0x9e74d1b791e07e48, 0x775ea264cf55347e}, -+ {0xc612062576589dda, 0x95364afe032a819e}, -+ {0xf79687aed3eec551, 0x3a83ddbd83f52205}, -+ {0x9abe14cd44753b52, 0xc4926a9672793543}, -+ {0xc16d9a0095928a27, 0x75b7053c0f178294}, -+ {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, -+ {0x971da05074da7bee, 0xd3f6fc16ebca5e04}, -+ {0xbce5086492111aea, 0x88f4bb1ca6bcf585}, -+ {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6}, -+ {0x9392ee8e921d5d07, 0x3aff322e62439fd0}, -+ {0xb877aa3236a4b449, 0x09befeb9fad487c3}, -+ {0xe69594bec44de15b, 0x4c2ebe687989a9b4}, -+ {0x901d7cf73ab0acd9, 0x0f9d37014bf60a11}, -+ {0xb424dc35095cd80f, 0x538484c19ef38c95}, -+ {0xe12e13424bb40e13, 0x2865a5f206b06fba}, -+ {0x8cbccc096f5088cb, 0xf93f87b7442e45d4}, -+ {0xafebff0bcb24aafe, 0xf78f69a51539d749}, -+ {0xdbe6fecebdedd5be, 0xb573440e5a884d1c}, -+ {0x89705f4136b4a597, 0x31680a88f8953031}, -+ {0xabcc77118461cefc, 0xfdc20d2b36ba7c3e}, -+ {0xd6bf94d5e57a42bc, 0x3d32907604691b4d}, -+ {0x8637bd05af6c69b5, 0xa63f9a49c2c1b110}, -+ {0xa7c5ac471b478423, 0x0fcf80dc33721d54}, -+ {0xd1b71758e219652b, 0xd3c36113404ea4a9}, -+ {0x83126e978d4fdf3b, 0x645a1cac083126ea}, -+ {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4}, -+ {0xcccccccccccccccc, 0xcccccccccccccccd}, -+ {0x8000000000000000, 0x0000000000000000}, -+ {0xa000000000000000, 0x0000000000000000}, -+ {0xc800000000000000, 0x0000000000000000}, -+ {0xfa00000000000000, 0x0000000000000000}, -+ {0x9c40000000000000, 0x0000000000000000}, -+ {0xc350000000000000, 0x0000000000000000}, -+ {0xf424000000000000, 0x0000000000000000}, -+ {0x9896800000000000, 0x0000000000000000}, -+ {0xbebc200000000000, 0x0000000000000000}, -+ {0xee6b280000000000, 0x0000000000000000}, -+ {0x9502f90000000000, 0x0000000000000000}, -+ {0xba43b74000000000, 0x0000000000000000}, -+ {0xe8d4a51000000000, 0x0000000000000000}, -+ {0x9184e72a00000000, 0x0000000000000000}, -+ {0xb5e620f480000000, 0x0000000000000000}, -+ {0xe35fa931a0000000, 0x0000000000000000}, -+ {0x8e1bc9bf04000000, 0x0000000000000000}, -+ {0xb1a2bc2ec5000000, 0x0000000000000000}, -+ {0xde0b6b3a76400000, 0x0000000000000000}, -+ {0x8ac7230489e80000, 0x0000000000000000}, -+ {0xad78ebc5ac620000, 0x0000000000000000}, -+ {0xd8d726b7177a8000, 0x0000000000000000}, -+ {0x878678326eac9000, 0x0000000000000000}, -+ {0xa968163f0a57b400, 0x0000000000000000}, -+ {0xd3c21bcecceda100, 0x0000000000000000}, -+ {0x84595161401484a0, 0x0000000000000000}, -+ {0xa56fa5b99019a5c8, 0x0000000000000000}, -+ {0xcecb8f27f4200f3a, 0x0000000000000000}, -+ {0x813f3978f8940984, 0x4000000000000000}, -+ {0xa18f07d736b90be5, 0x5000000000000000}, -+ {0xc9f2c9cd04674ede, 0xa400000000000000}, -+ {0xfc6f7c4045812296, 0x4d00000000000000}, -+ {0x9dc5ada82b70b59d, 0xf020000000000000}, -+ {0xc5371912364ce305, 0x6c28000000000000}, -+ {0xf684df56c3e01bc6, 0xc732000000000000}, -+ {0x9a130b963a6c115c, 0x3c7f400000000000}, -+ {0xc097ce7bc90715b3, 0x4b9f100000000000}, -+ {0xf0bdc21abb48db20, 0x1e86d40000000000}, -+ {0x96769950b50d88f4, 0x1314448000000000}, -+ {0xbc143fa4e250eb31, 0x17d955a000000000}, -+ {0xeb194f8e1ae525fd, 0x5dcfab0800000000}, -+ {0x92efd1b8d0cf37be, 0x5aa1cae500000000}, -+ {0xb7abc627050305ad, 0xf14a3d9e40000000}, -+ {0xe596b7b0c643c719, 0x6d9ccd05d0000000}, -+ {0x8f7e32ce7bea5c6f, 0xe4820023a2000000}, -+ {0xb35dbf821ae4f38b, 0xdda2802c8a800000}, -+ {0xe0352f62a19e306e, 0xd50b2037ad200000}, -+ {0x8c213d9da502de45, 0x4526f422cc340000}, -+ {0xaf298d050e4395d6, 0x9670b12b7f410000}, -+ {0xdaf3f04651d47b4c, 0x3c0cdd765f114000}, -+ {0x88d8762bf324cd0f, 0xa5880a69fb6ac800}, -+ {0xab0e93b6efee0053, 0x8eea0d047a457a00}, -+ {0xd5d238a4abe98068, 0x72a4904598d6d880}, -+ {0x85a36366eb71f041, 0x47a6da2b7f864750}, -+ {0xa70c3c40a64e6c51, 0x999090b65f67d924}, -+ {0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d}, -+ {0x82818f1281ed449f, 0xbff8f10e7a8921a4}, -+ {0xa321f2d7226895c7, 0xaff72d52192b6a0d}, -+ {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490}, -+ {0xfee50b7025c36a08, 0x02f236d04753d5b4}, -+ {0x9f4f2726179a2245, 0x01d762422c946590}, -+ {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5}, -+ {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2}, -+ {0x9b934c3b330c8577, 0x63cc55f49f88eb2f}, -+ {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb}, -+ {0xf316271c7fc3908a, 0x8bef464e3945ef7a}, -+ {0x97edd871cfda3a56, 0x97758bf0e3cbb5ac}, -+ {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317}, -+ {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd}, -+ {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a}, -+ {0xb975d6b6ee39e436, 0xb3e2fd538e122b44}, -+ {0xe7d34c64a9c85d44, 0x60dbbca87196b616}, -+ {0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd}, -+ {0xb51d13aea4a488dd, 0x6babab6398bdbe41}, -+ {0xe264589a4dcdab14, 0xc696963c7eed2dd1}, -+ {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2}, -+ {0xb0de65388cc8ada8, 0x3b25a55f43294bcb}, -+ {0xdd15fe86affad912, 0x49ef0eb713f39ebe}, -+ {0x8a2dbf142dfcc7ab, 0x6e3569326c784337}, -+ {0xacb92ed9397bf996, 0x49c2c37f07965404}, -+ {0xd7e77a8f87daf7fb, 0xdc33745ec97be906}, -+ {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3}, -+ {0xa8acd7c0222311bc, 0xc40832ea0d68ce0c}, -+ {0xd2d80db02aabd62b, 0xf50a3fa490c30190}, -+ {0x83c7088e1aab65db, 0x792667c6da79e0fa}, -+ {0xa4b8cab1a1563f52, 0x577001b891185938}, -+ {0xcde6fd5e09abcf26, 0xed4c0226b55e6f86}, -+ {0x80b05e5ac60b6178, 0x544f8158315b05b4}, -+ {0xa0dc75f1778e39d6, 0x696361ae3db1c721}, -+ {0xc913936dd571c84c, 0x03bc3a19cd1e38e9}, -+ {0xfb5878494ace3a5f, 0x04ab48a04065c723}, -+ {0x9d174b2dcec0e47b, 0x62eb0d64283f9c76}, -+ {0xc45d1df942711d9a, 0x3ba5d0bd324f8394}, -+ {0xf5746577930d6500, 0xca8f44ec7ee36479}, -+ {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb}, -+ {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e}, -+ {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e}, -+ {0x95d04aee3b80ece5, 0xbba1f1d158724a12}, -+ {0xbb445da9ca61281f, 0x2a8a6e45ae8edc97}, -+ {0xea1575143cf97226, 0xf52d09d71a3293bd}, -+ {0x924d692ca61be758, 0x593c2626705f9c56}, -+ {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c}, -+ {0xe498f455c38b997a, 0x0b6dfb9c0f956447}, -+ {0x8edf98b59a373fec, 0x4724bd4189bd5eac}, -+ {0xb2977ee300c50fe7, 0x58edec91ec2cb657}, -+ {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed}, -+ {0x8b865b215899f46c, 0xbd79e0d20082ee74}, -+ {0xae67f1e9aec07187, 0xecd8590680a3aa11}, -+ {0xda01ee641a708de9, 0xe80e6f4820cc9495}, -+ {0x884134fe908658b2, 0x3109058d147fdcdd}, -+ {0xaa51823e34a7eede, 0xbd4b46f0599fd415}, -+ {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a}, -+ {0x850fadc09923329e, 0x03e2cf6bc604ddb0}, -+ {0xa6539930bf6bff45, 0x84db8346b786151c}, -+ {0xcfe87f7cef46ff16, 0xe612641865679a63}, -+ {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e}, -+ {0xa26da3999aef7749, 0xe3be5e330f38f09d}, -+ {0xcb090c8001ab551c, 0x5cadf5bfd3072cc5}, -+ {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6}, -+ {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa}, -+ {0xc646d63501a1511d, 0xb281e1fd541501b8}, -+ {0xf7d88bc24209a565, 0x1f225a7ca91a4226}, -+ {0x9ae757596946075f, 0x3375788de9b06958}, -+ {0xc1a12d2fc3978937, 0x0052d6b1641c83ae}, -+ {0xf209787bb47d6b84, 0xc0678c5dbd23a49a}, -+ {0x9745eb4d50ce6332, 0xf840b7ba963646e0}, -+ {0xbd176620a501fbff, 0xb650e5a93bc3d898}, -+ {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe}, -+ {0x93ba47c980e98cdf, 0xc66f336c36b10137}, -+ {0xb8a8d9bbe123f017, 0xb80b0047445d4184}, -+ {0xe6d3102ad96cec1d, 0xa60dc059157491e5}, -+ {0x9043ea1ac7e41392, 0x87c89837ad68db2f}, -+ {0xb454e4a179dd1877, 0x29babe4598c311fb}, -+ {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a}, -+ {0x8ce2529e2734bb1d, 0x1899e4a65f58660c}, -+ {0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f}, -+ {0xdc21a1171d42645d, 0x76707543f4fa1f73}, -+ {0x899504ae72497eba, 0x6a06494a791c53a8}, -+ {0xabfa45da0edbde69, 0x0487db9d17636892}, -+ {0xd6f8d7509292d603, 0x45a9d2845d3c42b6}, -+ {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b2}, -+ {0xa7f26836f282b732, 0x8e6cac7768d7141e}, -+ {0xd1ef0244af2364ff, 0x3207d795430cd926}, -+ {0x8335616aed761f1f, 0x7f44e6bd49e807b8}, -+ {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6}, -+ {0xcd036837130890a1, 0x36dba887c37a8c0f}, -+ {0x802221226be55a64, 0xc2494954da2c9789}, -+ {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c}, -+ {0xc83553c5c8965d3d, 0x6f92829494e5acc7}, -+ {0xfa42a8b73abbf48c, 0xcb772339ba1f17f9}, -+ {0x9c69a97284b578d7, 0xff2a760414536efb}, -+ {0xc38413cf25e2d70d, 0xfef5138519684aba}, -+ {0xf46518c2ef5b8cd1, 0x7eb258665fc25d69}, -+ {0x98bf2f79d5993802, 0xef2f773ffbd97a61}, -+ {0xbeeefb584aff8603, 0xaafb550ffacfd8fa}, -+ {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38}, -+ {0x952ab45cfa97a0b2, 0xdd945a747bf26183}, -+ {0xba756174393d88df, 0x94f971119aeef9e4}, -+ {0xe912b9d1478ceb17, 0x7a37cd5601aab85d}, -+ {0x91abb422ccb812ee, 0xac62e055c10ab33a}, -+ {0xb616a12b7fe617aa, 0x577b986b314d6009}, -+ {0xe39c49765fdf9d94, 0xed5a7e85fda0b80b}, -+ {0x8e41ade9fbebc27d, 0x14588f13be847307}, -+ {0xb1d219647ae6b31c, 0x596eb2d8ae258fc8}, -+ {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb}, -+ {0x8aec23d680043bee, 0x25de7bb9480d5854}, -+ {0xada72ccc20054ae9, 0xaf561aa79a10ae6a}, -+ {0xd910f7ff28069da4, 0x1b2ba1518094da04}, -+ {0x87aa9aff79042286, 0x90fb44d2f05d0842}, -+ {0xa99541bf57452b28, 0x353a1607ac744a53}, -+ {0xd3fa922f2d1675f2, 0x42889b8997915ce8}, -+ {0x847c9b5d7c2e09b7, 0x69956135febada11}, -+ {0xa59bc234db398c25, 0x43fab9837e699095}, -+ {0xcf02b2c21207ef2e, 0x94f967e45e03f4bb}, -+ {0x8161afb94b44f57d, 0x1d1be0eebac278f5}, -+ {0xa1ba1ba79e1632dc, 0x6462d92a69731732}, -+ {0xca28a291859bbf93, 0x7d7b8f7503cfdcfe}, -+ {0xfcb2cb35e702af78, 0x5cda735244c3d43e}, -+ {0x9defbf01b061adab, 0x3a0888136afa64a7}, -+ {0xc56baec21c7a1916, 0x088aaa1845b8fdd0}, -+ {0xf6c69a72a3989f5b, 0x8aad549e57273d45}, -+ {0x9a3c2087a63f6399, 0x36ac54e2f678864b}, -+ {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd}, -+ {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5}, -+ {0x969eb7c47859e743, 0x9f644ae5a4b1b325}, -+ {0xbc4665b596706114, 0x873d5d9f0dde1fee}, -+ {0xeb57ff22fc0c7959, 0xa90cb506d155a7ea}, -+ {0x9316ff75dd87cbd8, 0x09a7f12442d588f2}, -+ {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb2f}, -+ {0xe5d3ef282a242e81, 0x8f1668c8a86da5fa}, -+ {0x8fa475791a569d10, 0xf96e017d694487bc}, -+ {0xb38d92d760ec4455, 0x37c981dcc395a9ac}, -+ {0xe070f78d3927556a, 0x85bbe253f47b1417}, -+ {0x8c469ab843b89562, 0x93956d7478ccec8e}, -+ {0xaf58416654a6babb, 0x387ac8d1970027b2}, -+ {0xdb2e51bfe9d0696a, 0x06997b05fcc0319e}, -+ {0x88fcf317f22241e2, 0x441fece3bdf81f03}, -+ {0xab3c2fddeeaad25a, 0xd527e81cad7626c3}, -+ {0xd60b3bd56a5586f1, 0x8a71e223d8d3b074}, -+ {0x85c7056562757456, 0xf6872d5667844e49}, -+ {0xa738c6bebb12d16c, 0xb428f8ac016561db}, -+ {0xd106f86e69d785c7, 0xe13336d701beba52}, -+ {0x82a45b450226b39c, 0xecc0024661173473}, -+ {0xa34d721642b06084, 0x27f002d7f95d0190}, -+ {0xcc20ce9bd35c78a5, 0x31ec038df7b441f4}, -+ {0xff290242c83396ce, 0x7e67047175a15271}, -+ {0x9f79a169bd203e41, 0x0f0062c6e984d386}, -+ {0xc75809c42c684dd1, 0x52c07b78a3e60868}, -+ {0xf92e0c3537826145, 0xa7709a56ccdf8a82}, -+ {0x9bbcc7a142b17ccb, 0x88a66076400bb691}, -+ {0xc2abf989935ddbfe, 0x6acff893d00ea435}, -+ {0xf356f7ebf83552fe, 0x0583f6b8c4124d43}, -+ {0x98165af37b2153de, 0xc3727a337a8b704a}, -+ {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c}, -+ {0xeda2ee1c7064130c, 0x1162def06f79df73}, -+ {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8}, -+ {0xb9a74a0637ce2ee1, 0x6d953e2bd7173692}, -+ {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437}, -+ {0x910ab1d4db9914a0, 0x1d9c9892400a22a2}, -+ {0xb54d5e4a127f59c8, 0x2503beb6d00cab4b}, -+ {0xe2a0b5dc971f303a, 0x2e44ae64840fd61d}, -+ {0x8da471a9de737e24, 0x5ceaecfed289e5d2}, -+ {0xb10d8e1456105dad, 0x7425a83e872c5f47}, -+ {0xdd50f1996b947518, 0xd12f124e28f77719}, -+ {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f}, -+ {0xace73cbfdc0bfb7b, 0x636cc64d1001550b}, -+ {0xd8210befd30efa5a, 0x3c47f7e05401aa4e}, -+ {0x8714a775e3e95c78, 0x65acfaec34810a71}, -+ {0xa8d9d1535ce3b396, 0x7f1839a741a14d0d}, -+ {0xd31045a8341ca07c, 0x1ede48111209a050}, -+ {0x83ea2b892091e44d, 0x934aed0aab460432}, -+ {0xa4e4b66b68b65d60, 0xf81da84d5617853f}, -+ {0xce1de40642e3f4b9, 0x36251260ab9d668e}, -+ {0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019}, -+ {0xa1075a24e4421730, 0xb24cf65b8612f81f}, -+ {0xc94930ae1d529cfc, 0xdee033f26797b627}, -+ {0xfb9b7cd9a4a7443c, 0x169840ef017da3b1}, -+ {0x9d412e0806e88aa5, 0x8e1f289560ee864e}, -+ {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2}, -+ {0xf5b5d7ec8acb58a2, 0xae10af696774b1db}, -+ {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29}, -+ {0xbff610b0cc6edd3f, 0x17fd090a58d32af3}, -+ {0xeff394dcff8a948e, 0xddfc4b4cef07f5b0}, -+ {0x95f83d0a1fb69cd9, 0x4abdaf101564f98e}, -+ {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1}, -+ {0xea53df5fd18d5513, 0x84c86189216dc5ed}, -+ {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4}, -+ {0xb7118682dbb66a77, 0x3fbc8c33221dc2a1}, -+ {0xe4d5e82392a40515, 0x0fabaf3feaa5334a}, -+ {0x8f05b1163ba6832d, 0x29cb4d87f2a7400e}, -+ {0xb2c71d5bca9023f8, 0x743e20e9ef511012}, -+ {0xdf78e4b2bd342cf6, 0x914da9246b255416}, -+ {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e}, -+ {0xae9672aba3d0c320, 0xa184ac2473b529b1}, -+ {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e}, -+ {0x8865899617fb1871, 0x7e2fa67c7a658892}, -+ {0xaa7eebfb9df9de8d, 0xddbb901b98feeab7}, -+ {0xd51ea6fa85785631, 0x552a74227f3ea565}, -+ {0x8533285c936b35de, 0xd53a88958f87275f}, -+ {0xa67ff273b8460356, 0x8a892abaf368f137}, -+ {0xd01fef10a657842c, 0x2d2b7569b0432d85}, -+ {0x8213f56a67f6b29b, 0x9c3b29620e29fc73}, -+ {0xa298f2c501f45f42, 0x8349f3ba91b47b8f}, -+ {0xcb3f2f7642717713, 0x241c70a936219a73}, -+ {0xfe0efb53d30dd4d7, 0xed238cd383aa0110}, -+ {0x9ec95d1463e8a506, 0xf4363804324a40aa}, -+ {0xc67bb4597ce2ce48, 0xb143c6053edcd0d5}, -+ {0xf81aa16fdc1b81da, 0xdd94b7868e94050a}, -+ {0x9b10a4e5e9913128, 0xca7cf2b4191c8326}, -+ {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0}, -+ {0xf24a01a73cf2dccf, 0xbc633b39673c8cec}, -+ {0x976e41088617ca01, 0xd5be0503e085d813}, -+ {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18}, -+ {0xec9c459d51852ba2, 0xddf8e7d60ed1219e}, -+ {0x93e1ab8252f33b45, 0xcabb90e5c942b503}, -+ {0xb8da1662e7b00a17, 0x3d6a751f3b936243}, -+ {0xe7109bfba19c0c9d, 0x0cc512670a783ad4}, -+ {0x906a617d450187e2, 0x27fb2b80668b24c5}, -+ {0xb484f9dc9641e9da, 0xb1f9f660802dedf6}, -+ {0xe1a63853bbd26451, 0x5e7873f8a0396973}, -+ {0x8d07e33455637eb2, 0xdb0b487b6423e1e8}, -+ {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62}, -+ {0xdc5c5301c56b75f7, 0x7641a140cc7810fb}, -+ {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d}, -+ {0xac2820d9623bf429, 0x546345fa9fbdcd44}, -+ {0xd732290fbacaf133, 0xa97c177947ad4095}, -+ {0x867f59a9d4bed6c0, 0x49ed8eabcccc485d}, -+ {0xa81f301449ee8c70, 0x5c68f256bfff5a74}, -+ {0xd226fc195c6a2f8c, 0x73832eec6fff3111}, -+ {0x83585d8fd9c25db7, 0xc831fd53c5ff7eab}, -+ {0xa42e74f3d032f525, 0xba3e7ca8b77f5e55}, -+ {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb}, -+ {0x80444b5e7aa7cf85, 0x7980d163cf5b81b3}, -+ {0xa0555e361951c366, 0xd7e105bcc332621f}, -+ {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7}, -+ {0xfa856334878fc150, 0xb14f98f6f0feb951}, -+ {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3}, -+ {0xc3b8358109e84f07, 0x0a862f80ec4700c8}, -+ {0xf4a642e14c6262c8, 0xcd27bb612758c0fa}, -+ {0x98e7e9cccfbd7dbd, 0x8038d51cb897789c}, -+ {0xbf21e44003acdd2c, 0xe0470a63e6bd56c3}, -+ {0xeeea5d5004981478, 0x1858ccfce06cac74}, -+ {0x95527a5202df0ccb, 0x0f37801e0c43ebc8}, -+ {0xbaa718e68396cffd, 0xd30560258f54e6ba}, -+ {0xe950df20247c83fd, 0x47c6b82ef32a2069}, -+ {0x91d28b7416cdd27e, 0x4cdc331d57fa5441}, -+ {0xb6472e511c81471d, 0xe0133fe4adf8e952}, -+ {0xe3d8f9e563a198e5, 0x58180fddd97723a6}, -+ {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648}, -+ {0xb201833b35d63f73, 0x2cd2cc6551e513da}, -+ {0xde81e40a034bcf4f, 0xf8077f7ea65e58d1}, -+ {0x8b112e86420f6191, 0xfb04afaf27faf782}, -+ {0xadd57a27d29339f6, 0x79c5db9af1f9b563}, -+ {0xd94ad8b1c7380874, 0x18375281ae7822bc}, -+ {0x87cec76f1c830548, 0x8f2293910d0b15b5}, -+ {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb22}, -+ {0xd433179d9c8cb841, 0x5fa60692a46151eb}, -+ {0x849feec281d7f328, 0xdbc7c41ba6bcd333}, -+ {0xa5c7ea73224deff3, 0x12b9b522906c0800}, -+ {0xcf39e50feae16bef, 0xd768226b34870a00}, -+ {0x81842f29f2cce375, 0xe6a1158300d46640}, -+ {0xa1e53af46f801c53, 0x60495ae3c1097fd0}, -+ {0xca5e89b18b602368, 0x385bb19cb14bdfc4}, -+ {0xfcf62c1dee382c42, 0x46729e03dd9ed7b5}, -+ {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d1}, -+ {0xc5a05277621be293, 0xc7098b7305241885}, -+ { 0xf70867153aa2db38, -+ 0xb8cbee4fc66d1ea7 } - #else -+ {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, -+ {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, -+ {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, -+ {0x86a8d39ef77164bc, 0xae5dff9c02033198}, -+ {0xd98ddaee19068c76, 0x3badd624dd9b0958}, -+ {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, -+ {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, -+ {0xe55990879ddcaabd, 0xcc420a6a101d0516}, -+ {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, -+ {0x95a8637627989aad, 0xdde7001379a44aa9}, -+ {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, -+ {0xc350000000000000, 0x0000000000000000}, -+ {0x9dc5ada82b70b59d, 0xf020000000000000}, -+ {0xfee50b7025c36a08, 0x02f236d04753d5b4}, -+ {0xcde6fd5e09abcf26, 0xed4c0226b55e6f86}, -+ {0xa6539930bf6bff45, 0x84db8346b786151c}, -+ {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b2}, -+ {0xd910f7ff28069da4, 0x1b2ba1518094da04}, -+ {0xaf58416654a6babb, 0x387ac8d1970027b2}, -+ {0x8da471a9de737e24, 0x5ceaecfed289e5d2}, -+ {0xe4d5e82392a40515, 0x0fabaf3feaa5334a}, -+ {0xb8da1662e7b00a17, 0x3d6a751f3b936243}, -+ { 0x95527a5202df0ccb, -+ 0x0f37801e0c43ebc8 } -+#endif -+ }; -+ -+#if FMT_USE_FULL_CACHE_DRAGONBOX -+ return pow10_significands[k - float_info<double>::min_k]; -+#else -+ static constexpr const uint64_t powers_of_5_64[] = { -+ 0x0000000000000001, 0x0000000000000005, 0x0000000000000019, -+ 0x000000000000007d, 0x0000000000000271, 0x0000000000000c35, -+ 0x0000000000003d09, 0x000000000001312d, 0x000000000005f5e1, -+ 0x00000000001dcd65, 0x00000000009502f9, 0x0000000002e90edd, -+ 0x000000000e8d4a51, 0x0000000048c27395, 0x000000016bcc41e9, -+ 0x000000071afd498d, 0x0000002386f26fc1, 0x000000b1a2bc2ec5, -+ 0x000003782dace9d9, 0x00001158e460913d, 0x000056bc75e2d631, -+ 0x0001b1ae4d6e2ef5, 0x000878678326eac9, 0x002a5a058fc295ed, -+ 0x00d3c21bcecceda1, 0x0422ca8b0a00a425, 0x14adf4b7320334b9}; -+ -+ static constexpr const uint32_t pow10_recovery_errors[] = { -+ 0x50001400, 0x54044100, 0x54014555, 0x55954415, 0x54115555, 0x00000001, -+ 0x50000000, 0x00104000, 0x54010004, 0x05004001, 0x55555544, 0x41545555, -+ 0x54040551, 0x15445545, 0x51555514, 0x10000015, 0x00101100, 0x01100015, -+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04450514, 0x45414110, -+ 0x55555145, 0x50544050, 0x15040155, 0x11054140, 0x50111514, 0x11451454, -+ 0x00400541, 0x00000000, 0x55555450, 0x10056551, 0x10054011, 0x55551014, -+ 0x69514555, 0x05151109, 0x00155555}; -+ - static const int compression_ratio = 27; - - // Compute base index. -@@ -1897,8 +1805,7 @@ template <> struct cache_accessor<double> { - int offset = k - kb; - - // Get base cache. -- uint128_wrapper base_cache = -- data::dragonbox_pow10_significands_128[cache_index]; -+ uint128_wrapper base_cache = pow10_significands[cache_index]; - if (offset == 0) return base_cache; - - // Compute the required amount of bit-shift. -@@ -1906,7 +1813,7 @@ template <> struct cache_accessor<double> { - FMT_ASSERT(alpha > 0 && alpha < 64, "shifting error detected"); - - // Try to recover the real cache. -- uint64_t pow5 = data::powers_of_5_64[offset]; -+ uint64_t pow5 = powers_of_5_64[offset]; - uint128_wrapper recovered_cache = umul128(base_cache.high(), pow5); - uint128_wrapper middle_low = - umul128(base_cache.low() - (kb < 0 ? 1u : 0u), pow5); -@@ -1924,7 +1831,7 @@ template <> struct cache_accessor<double> { - - // Get error. - int error_idx = (k - float_info<double>::min_k) / 16; -- uint32_t error = (data::dragonbox_pow10_recovery_errors[error_idx] >> -+ uint32_t error = (pow10_recovery_errors[error_idx] >> - ((k - float_info<double>::min_k) % 16) * 2) & - 0x3; - -@@ -2010,7 +1917,7 @@ bool is_center_integer(typename float_info<T>::carrier_uint two_f, int exponent, - } - - // Remove trailing zeros from n and return the number of zeros removed (float) --FMT_ALWAYS_INLINE int remove_trailing_zeros(uint32_t& n) FMT_NOEXCEPT { -+FMT_INLINE int remove_trailing_zeros(uint32_t& n) FMT_NOEXCEPT { - #ifdef FMT_BUILTIN_CTZ - int t = FMT_BUILTIN_CTZ(n); - #else -@@ -2038,7 +1945,7 @@ FMT_ALWAYS_INLINE int remove_trailing_zeros(uint32_t& n) FMT_NOEXCEPT { - } - - // Removes trailing zeros and returns the number of zeros removed (double) --FMT_ALWAYS_INLINE int remove_trailing_zeros(uint64_t& n) FMT_NOEXCEPT { -+FMT_INLINE int remove_trailing_zeros(uint64_t& n) FMT_NOEXCEPT { - #ifdef FMT_BUILTIN_CTZLL - int t = FMT_BUILTIN_CTZLL(n); - #else -@@ -2124,8 +2031,7 @@ FMT_ALWAYS_INLINE int remove_trailing_zeros(uint64_t& n) FMT_NOEXCEPT { - - // The main algorithm for shorter interval case - template <class T> --FMT_ALWAYS_INLINE FMT_SAFEBUFFERS decimal_fp<T> shorter_interval_case( -- int exponent) FMT_NOEXCEPT { -+FMT_INLINE decimal_fp<T> shorter_interval_case(int exponent) FMT_NOEXCEPT { - decimal_fp<T> ret_value; - // Compute k and beta - const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent); -@@ -2171,8 +2077,7 @@ FMT_ALWAYS_INLINE FMT_SAFEBUFFERS decimal_fp<T> shorter_interval_case( - return ret_value; - } - --template <typename T> --FMT_SAFEBUFFERS decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT { -+template <typename T> decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT { - // Step 1: integer promotion & Schubfach multiplier calculation. - - using carrier_uint = typename float_info<T>::carrier_uint; -@@ -2308,7 +2213,7 @@ small_divisor_case_label: - - // Formats value using a variation of the Fixed-Precision Positive - // Floating-Point Printout ((FPP)^2) algorithm by Steele & White: --// https://fmt.dev/p372-steele.pdf. -+// https://fmt.dev/papers/p372-steele.pdf. - template <typename Double> - void fallback_format(Double d, int num_digits, bool binary32, buffer<char>& buf, - int& exp10) { -@@ -2571,11 +2476,11 @@ int snprintf_float(T value, int precision, float_specs specs, - --exp_pos; - } while (*exp_pos != 'e'); - char sign = exp_pos[1]; -- assert(sign == '+' || sign == '-'); -+ FMT_ASSERT(sign == '+' || sign == '-', ""); - int exp = 0; - auto p = exp_pos + 2; // Skip 'e' and sign. - do { -- assert(is_digit(*p)); -+ FMT_ASSERT(is_digit(*p), ""); - exp = exp * 10 + (*p++ - '0'); - } while (p != end); - if (sign == '-') exp = -exp; -@@ -2592,71 +2497,11 @@ int snprintf_float(T value, int precision, float_specs specs, - return exp - fraction_size; - } - } -- --// A public domain branchless UTF-8 decoder by Christopher Wellons: --// https://github.com/skeeto/branchless-utf8 --/* Decode the next character, c, from buf, reporting errors in e. -- * -- * Since this is a branchless decoder, four bytes will be read from the -- * buffer regardless of the actual length of the next character. This -- * means the buffer _must_ have at least three bytes of zero padding -- * following the end of the data stream. -- * -- * Errors are reported in e, which will be non-zero if the parsed -- * character was somehow invalid: invalid byte sequence, non-canonical -- * encoding, or a surrogate half. -- * -- * The function returns a pointer to the next character. When an error -- * occurs, this pointer will be a guess that depends on the particular -- * error, but it will always advance at least one byte. -- */ --inline const char* utf8_decode(const char* buf, uint32_t* c, int* e) { -- static const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07}; -- static const uint32_t mins[] = {4194304, 0, 128, 2048, 65536}; -- static const int shiftc[] = {0, 18, 12, 6, 0}; -- static const int shifte[] = {0, 6, 4, 2, 0}; -- -- int len = code_point_length(buf); -- const char* next = buf + len; -- -- // Assume a four-byte character and load four bytes. Unused bits are -- // shifted out. -- auto s = reinterpret_cast<const unsigned char*>(buf); -- *c = uint32_t(s[0] & masks[len]) << 18; -- *c |= uint32_t(s[1] & 0x3f) << 12; -- *c |= uint32_t(s[2] & 0x3f) << 6; -- *c |= uint32_t(s[3] & 0x3f) << 0; -- *c >>= shiftc[len]; -- -- // Accumulate the various error conditions. -- *e = (*c < mins[len]) << 6; // non-canonical encoding -- *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half? -- *e |= (*c > 0x10FFFF) << 8; // out of range? -- *e |= (s[1] & 0xc0) >> 2; -- *e |= (s[2] & 0xc0) >> 4; -- *e |= (s[3]) >> 6; -- *e ^= 0x2a; // top two bits of each tail byte correct? -- *e >>= shifte[len]; -- -- return next; --} -- --struct stringifier { -- template <typename T> FMT_INLINE std::string operator()(T value) const { -- return to_string(value); -- } -- std::string operator()(basic_format_arg<format_context>::handle h) const { -- memory_buffer buf; -- format_parse_context parse_ctx({}); -- format_context format_ctx(buffer_appender<char>(buf), {}, {}); -- h.format(parse_ctx, format_ctx); -- return to_string(buf); -- } --}; - } // namespace detail - - template <> struct formatter<detail::bigint> { -- format_parse_context::iterator parse(format_parse_context& ctx) { -+ FMT_CONSTEXPR format_parse_context::iterator parse( -+ format_parse_context& ctx) { - return ctx.begin(); - } - -@@ -2667,23 +2512,21 @@ template <> struct formatter<detail::bigint> { - for (auto i = n.bigits_.size(); i > 0; --i) { - auto value = n.bigits_[i - 1u]; - if (first) { -- out = format_to(out, "{:x}", value); -+ out = format_to(out, FMT_STRING("{:x}"), value); - first = false; - continue; - } -- out = format_to(out, "{:08x}", value); -+ out = format_to(out, FMT_STRING("{:08x}"), value); - } - if (n.exp_ > 0) -- out = format_to(out, "p{}", n.exp_ * detail::bigint::bigit_bits); -+ out = format_to(out, FMT_STRING("p{}"), -+ n.exp_ * detail::bigint::bigit_bits); - return out; - } - }; - - FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { -- auto transcode = [this](const char* p) { -- auto cp = uint32_t(); -- auto error = 0; -- p = utf8_decode(p, &cp, &error); -+ for_each_codepoint(s, [this](uint32_t cp, int error) { - if (error != 0) FMT_THROW(std::runtime_error("invalid utf8")); - if (cp <= 0xFFFF) { - buffer_.push_back(static_cast<wchar_t>(cp)); -@@ -2692,42 +2535,16 @@ FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { - buffer_.push_back(static_cast<wchar_t>(0xD800 + (cp >> 10))); - buffer_.push_back(static_cast<wchar_t>(0xDC00 + (cp & 0x3FF))); - } -- return p; -- }; -- auto p = s.data(); -- const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. -- if (s.size() >= block_size) { -- for (auto end = p + s.size() - block_size + 1; p < end;) p = transcode(p); -- } -- if (auto num_chars_left = s.data() + s.size() - p) { -- char buf[2 * block_size - 1] = {}; -- memcpy(buf, p, to_unsigned(num_chars_left)); -- p = buf; -- do { -- p = transcode(p); -- } while (p - buf < num_chars_left); -- } -+ }); - buffer_.push_back(0); - } - - FMT_FUNC void format_system_error(detail::buffer<char>& out, int error_code, -- string_view message) FMT_NOEXCEPT { -+ const char* message) FMT_NOEXCEPT { - FMT_TRY { -- memory_buffer buf; -- buf.resize(inline_buffer_size); -- for (;;) { -- char* system_message = &buf[0]; -- int result = -- detail::safe_strerror(error_code, system_message, buf.size()); -- if (result == 0) { -- format_to(detail::buffer_appender<char>(out), "{}: {}", message, -- system_message); -- return; -- } -- if (result != ERANGE) -- break; // Can't get error message, report error code instead. -- buf.resize(buf.size() * 2); -- } -+ auto ec = std::error_code(error_code, std::generic_category()); -+ write(std::back_inserter(out), std::system_error(ec, message).what()); -+ return; - } - FMT_CATCH(...) {} - format_error_code(out, error_code, message); -@@ -2738,18 +2555,15 @@ FMT_FUNC void detail::error_handler::on_error(const char* message) { - } - - FMT_FUNC void report_system_error(int error_code, -- fmt::string_view message) FMT_NOEXCEPT { -+ const char* message) FMT_NOEXCEPT { - report_error(format_system_error, error_code, message); - } - --FMT_FUNC std::string detail::vformat(string_view format_str, format_args args) { -- if (format_str.size() == 2 && equal2(format_str.data(), "{}")) { -- auto arg = args.get(0); -- if (!arg) error_handler().on_error("argument not found"); -- return visit_format_arg(stringifier(), arg); -- } -- memory_buffer buffer; -- detail::vformat_to(buffer, format_str, args); -+FMT_FUNC std::string vformat(string_view fmt, format_args args) { -+ // Don't optimize the "{}" case to keep the binary size small and because it -+ // can be better optimized in fmt::format anyway. -+ auto buffer = memory_buffer(); -+ detail::vformat_to(buffer, fmt, args); - return to_string(buffer); - } - -@@ -2761,24 +2575,30 @@ extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( // - } // namespace detail - #endif - --FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) { -- memory_buffer buffer; -- detail::vformat_to(buffer, format_str, -- basic_format_args<buffer_context<char>>(args)); -+namespace detail { -+FMT_FUNC void print(std::FILE* f, string_view text) { - #ifdef _WIN32 - auto fd = _fileno(f); - if (_isatty(fd)) { -- detail::utf8_to_utf16 u16(string_view(buffer.data(), buffer.size())); -+ detail::utf8_to_utf16 u16(string_view(text.data(), text.size())); - auto written = detail::dword(); -- if (!detail::WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)), -- u16.c_str(), static_cast<uint32_t>(u16.size()), -- &written, nullptr)) { -- FMT_THROW(format_error("failed to write to console")); -+ if (detail::WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)), -+ u16.c_str(), static_cast<uint32_t>(u16.size()), -+ &written, nullptr)) { -+ return; - } -- return; -+ // Fallback to fwrite on failure. It can happen if the output has been -+ // redirected to NUL. - } - #endif -- detail::fwrite_fully(buffer.data(), 1, buffer.size(), f); -+ detail::fwrite_fully(text.data(), 1, text.size(), f); -+} -+} // namespace detail -+ -+FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) { -+ memory_buffer buffer; -+ detail::vformat_to(buffer, format_str, args); -+ detail::print(f, {buffer.data(), buffer.size()}); - } - - #ifdef _WIN32 -diff --git a/include/spdlog/fmt/bundled/format.h b/include/spdlog/fmt/bundled/format.h -index 1a037b02..03ae1c96 100644 ---- a/include/spdlog/fmt/bundled/format.h -+++ b/include/spdlog/fmt/bundled/format.h -@@ -33,13 +33,13 @@ - #ifndef FMT_FORMAT_H_ - #define FMT_FORMAT_H_ - --#include <algorithm> --#include <cerrno> --#include <cmath> --#include <cstdint> --#include <limits> --#include <memory> --#include <stdexcept> -+#include <cmath> // std::signbit -+#include <cstdint> // uint32_t -+#include <limits> // std::numeric_limits -+#include <memory> // std::uninitialized_copy -+#include <stdexcept> // std::runtime_error -+#include <system_error> // std::system_error -+#include <utility> // std::swap - - #include "core.h" - -@@ -69,30 +69,10 @@ - # define FMT_NOINLINE - #endif - --#if __cplusplus == 201103L || __cplusplus == 201402L --# if defined(__INTEL_COMPILER) || defined(__PGI) --# define FMT_FALLTHROUGH --# elif defined(__clang__) --# define FMT_FALLTHROUGH [[clang::fallthrough]] --# elif FMT_GCC_VERSION >= 700 && \ -- (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) --# define FMT_FALLTHROUGH [[gnu::fallthrough]] --# else --# define FMT_FALLTHROUGH --# endif --#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) || \ -- (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) --# define FMT_FALLTHROUGH [[fallthrough]] -+#if FMT_MSC_VER -+# define FMT_MSC_DEFAULT = default - #else --# define FMT_FALLTHROUGH --#endif -- --#ifndef FMT_MAYBE_UNUSED --# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) --# define FMT_MAYBE_UNUSED [[maybe_unused]] --# else --# define FMT_MAYBE_UNUSED --# endif -+# define FMT_MSC_DEFAULT - #endif - - #ifndef FMT_THROW -@@ -113,10 +93,9 @@ FMT_END_NAMESPACE - # define FMT_THROW(x) throw x - # endif - # else --# define FMT_THROW(x) \ -- do { \ -- static_cast<void>(sizeof(x)); \ -- FMT_ASSERT(false, ""); \ -+# define FMT_THROW(x) \ -+ do { \ -+ FMT_ASSERT(false, (x).what()); \ - } while (false) - # endif - #endif -@@ -129,6 +108,27 @@ FMT_END_NAMESPACE - # define FMT_CATCH(x) if (false) - #endif - -+#ifndef FMT_DEPRECATED -+# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900 -+# define FMT_DEPRECATED [[deprecated]] -+# else -+# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__) -+# define FMT_DEPRECATED __attribute__((deprecated)) -+# elif FMT_MSC_VER -+# define FMT_DEPRECATED __declspec(deprecated) -+# else -+# define FMT_DEPRECATED /* deprecated */ -+# endif -+# endif -+#endif -+ -+// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers. -+#if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC -+# define FMT_DEPRECATED_ALIAS -+#else -+# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED -+#endif -+ - #ifndef FMT_USE_USER_DEFINED_LITERALS - // EDG based compilers (Intel, NVIDIA, Elbrus, etc), GCC and MSVC support UDLs. - # if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \ -@@ -140,36 +140,10 @@ FMT_END_NAMESPACE - # endif - #endif - --#ifndef FMT_USE_UDL_TEMPLATE --// EDG frontend based compilers (icc, nvcc, PGI, etc) and GCC < 6.4 do not --// properly support UDL templates and GCC >= 9 warns about them. --# if FMT_USE_USER_DEFINED_LITERALS && \ -- (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 501) && \ -- ((FMT_GCC_VERSION >= 604 && __cplusplus >= 201402L) || \ -- FMT_CLANG_VERSION >= 304) && \ -- !defined(__PGI) && !defined(__NVCC__) --# define FMT_USE_UDL_TEMPLATE 1 --# else --# define FMT_USE_UDL_TEMPLATE 0 --# endif --#endif -- --#ifndef FMT_USE_FLOAT --# define FMT_USE_FLOAT 1 --#endif -- --#ifndef FMT_USE_DOUBLE --# define FMT_USE_DOUBLE 1 --#endif -- --#ifndef FMT_USE_LONG_DOUBLE --# define FMT_USE_LONG_DOUBLE 1 --#endif -- - // Defining FMT_REDUCE_INT_INSTANTIATIONS to 1, will reduce the number of --// int_writer template instances to just one by only using the largest integer --// type. This results in a reduction in binary size but will cause a decrease in --// integer formatting performance. -+// integer formatter template instantiations to just one by only using the -+// largest integer type. This results in a reduction in binary size but will -+// cause a decrease in integer formatting performance. - #if !defined(FMT_REDUCE_INT_INSTANTIATIONS) - # define FMT_REDUCE_INT_INSTANTIATIONS 0 - #endif -@@ -196,33 +170,33 @@ FMT_END_NAMESPACE - // Some compilers masquerade as both MSVC and GCC-likes or otherwise support - // __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the - // MSVC intrinsics if the clz and clzll builtins are not available. --#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && \ -- !defined(FMT_BUILTIN_CTZLL) && !defined(_MANAGED) -+#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(FMT_BUILTIN_CTZLL) - FMT_BEGIN_NAMESPACE - namespace detail { - // Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. --# ifndef __clang__ -+# if !defined(__clang__) -+# pragma managed(push, off) - # pragma intrinsic(_BitScanForward) - # pragma intrinsic(_BitScanReverse) --# endif --# if defined(_WIN64) && !defined(__clang__) --# pragma intrinsic(_BitScanForward64) --# pragma intrinsic(_BitScanReverse64) -+# if defined(_WIN64) -+# pragma intrinsic(_BitScanForward64) -+# pragma intrinsic(_BitScanReverse64) -+# endif - # endif - --inline int clz(uint32_t x) { -+inline auto clz(uint32_t x) -> int { - unsigned long r = 0; - _BitScanReverse(&r, x); - FMT_ASSERT(x != 0, ""); - // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, - // which the callers guarantee to not happen. -- FMT_SUPPRESS_MSC_WARNING(6102) -+ FMT_MSC_WARNING(suppress : 6102) - return 31 ^ static_cast<int>(r); - } - # define FMT_BUILTIN_CLZ(n) detail::clz(n) - --inline int clzll(uint64_t x) { -+inline auto clzll(uint64_t x) -> int { - unsigned long r = 0; - # ifdef _WIN64 - _BitScanReverse64(&r, x); -@@ -233,24 +207,24 @@ inline int clzll(uint64_t x) { - _BitScanReverse(&r, static_cast<uint32_t>(x)); - # endif - FMT_ASSERT(x != 0, ""); -- FMT_SUPPRESS_MSC_WARNING(6102) // Suppress a bogus static analysis warning. -+ FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. - return 63 ^ static_cast<int>(r); - } - # define FMT_BUILTIN_CLZLL(n) detail::clzll(n) - --inline int ctz(uint32_t x) { -+inline auto ctz(uint32_t x) -> int { - unsigned long r = 0; - _BitScanForward(&r, x); - FMT_ASSERT(x != 0, ""); -- FMT_SUPPRESS_MSC_WARNING(6102) // Suppress a bogus static analysis warning. -+ FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. - return static_cast<int>(r); - } - # define FMT_BUILTIN_CTZ(n) detail::ctz(n) - --inline int ctzll(uint64_t x) { -+inline auto ctzll(uint64_t x) -> int { - unsigned long r = 0; - FMT_ASSERT(x != 0, ""); -- FMT_SUPPRESS_MSC_WARNING(6102) // Suppress a bogus static analysis warning. -+ FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. - # ifdef _WIN64 - _BitScanForward64(&r, x); - # else -@@ -263,30 +237,35 @@ inline int ctzll(uint64_t x) { - return static_cast<int>(r); - } - # define FMT_BUILTIN_CTZLL(n) detail::ctzll(n) -+# if !defined(__clang__) -+# pragma managed(pop) -+# endif - } // namespace detail - FMT_END_NAMESPACE - #endif - --// Enable the deprecated numeric alignment. --#ifndef FMT_DEPRECATED_NUMERIC_ALIGN --# define FMT_DEPRECATED_NUMERIC_ALIGN 0 --#endif -- - FMT_BEGIN_NAMESPACE - namespace detail { - -+#if __cplusplus >= 202002L || \ -+ (__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002) -+# define FMT_CONSTEXPR20 constexpr -+#else -+# define FMT_CONSTEXPR20 -+#endif -+ - // An equivalent of `*reinterpret_cast<Dest*>(&source)` that doesn't have - // undefined behavior (e.g. due to type aliasing). - // Example: uint64_t d = bit_cast<uint64_t>(2.718); - template <typename Dest, typename Source> --inline Dest bit_cast(const Source& source) { -+inline auto bit_cast(const Source& source) -> Dest { - static_assert(sizeof(Dest) == sizeof(Source), "size mismatch"); - Dest dest; - std::memcpy(&dest, &source, sizeof(dest)); - return dest; - } - --inline bool is_big_endian() { -+inline auto is_big_endian() -> bool { - const auto u = 1u; - struct bytes { - char data[sizeof(u)]; -@@ -309,26 +288,28 @@ struct fallback_uintptr { - }; - #ifdef UINTPTR_MAX - using uintptr_t = ::uintptr_t; --inline uintptr_t to_uintptr(const void* p) { return bit_cast<uintptr_t>(p); } -+inline auto to_uintptr(const void* p) -> uintptr_t { -+ return bit_cast<uintptr_t>(p); -+} - #else - using uintptr_t = fallback_uintptr; --inline fallback_uintptr to_uintptr(const void* p) { -+inline auto to_uintptr(const void* p) -> fallback_uintptr { - return fallback_uintptr(p); - } - #endif - - // Returns the largest possible value for type T. Same as - // std::numeric_limits<T>::max() but shorter and not affected by the max macro. --template <typename T> constexpr T max_value() { -+template <typename T> constexpr auto max_value() -> T { - return (std::numeric_limits<T>::max)(); - } --template <typename T> constexpr int num_bits() { -+template <typename T> constexpr auto num_bits() -> int { - return std::numeric_limits<T>::digits; - } - // std::numeric_limits<T>::digits may return 0 for 128-bit ints. --template <> constexpr int num_bits<int128_t>() { return 128; } --template <> constexpr int num_bits<uint128_t>() { return 128; } --template <> constexpr int num_bits<fallback_uintptr>() { -+template <> constexpr auto num_bits<int128_t>() -> int { return 128; } -+template <> constexpr auto num_bits<uint128_t>() -> int { return 128; } -+template <> constexpr auto num_bits<fallback_uintptr>() -> int { - return static_cast<int>(sizeof(void*) * - std::numeric_limits<unsigned char>::digits); - } -@@ -346,31 +327,35 @@ using iterator_t = decltype(std::begin(std::declval<T&>())); - template <typename T> using sentinel_t = decltype(std::end(std::declval<T&>())); - - // A workaround for std::string not having mutable data() until C++17. --template <typename Char> inline Char* get_data(std::basic_string<Char>& s) { -+template <typename Char> -+inline auto get_data(std::basic_string<Char>& s) -> Char* { - return &s[0]; - } - template <typename Container> --inline typename Container::value_type* get_data(Container& c) { -+inline auto get_data(Container& c) -> typename Container::value_type* { - return c.data(); - } - - #if defined(_SECURE_SCL) && _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, size_t size) { -+template <typename T> auto make_checked(T* p, size_t size) -> checked_ptr<T> { - return {p, size}; - } - #else - template <typename T> using checked_ptr = T*; --template <typename T> inline T* make_checked(T* p, size_t) { return p; } -+template <typename T> inline auto make_checked(T* p, size_t) -> T* { return p; } - #endif - -+// Attempts to reserve space for n extra characters in the output range. -+// Returns a pointer to the reserved range or a reference to it. - template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)> --#if FMT_CLANG_VERSION -+#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION - __attribute__((no_sanitize("undefined"))) - #endif --inline checked_ptr<typename Container::value_type> --reserve(std::back_insert_iterator<Container> it, size_t n) { -+inline auto -+reserve(std::back_insert_iterator<Container> it, size_t n) -+ -> checked_ptr<typename Container::value_type> { - Container& c = get_container(it); - size_t size = c.size(); - c.resize(size + n); -@@ -378,21 +363,26 @@ reserve(std::back_insert_iterator<Container> it, size_t n) { - } - - template <typename T> --inline buffer_appender<T> reserve(buffer_appender<T> it, size_t n) { -+inline auto reserve(buffer_appender<T> it, size_t n) -> buffer_appender<T> { - buffer<T>& buf = get_container(it); - buf.try_reserve(buf.size() + n); - return it; - } - --template <typename Iterator> inline Iterator& reserve(Iterator& it, size_t) { -+template <typename Iterator> -+constexpr auto reserve(Iterator& it, size_t) -> Iterator& { - return it; - } - -+template <typename OutputIt> -+using reserve_iterator = -+ remove_reference_t<decltype(reserve(std::declval<OutputIt&>(), 0))>; -+ - template <typename T, typename OutputIt> --constexpr T* to_pointer(OutputIt, size_t) { -+constexpr auto to_pointer(OutputIt, size_t) -> T* { - return nullptr; - } --template <typename T> T* to_pointer(buffer_appender<T> it, size_t n) { -+template <typename T> auto to_pointer(buffer_appender<T> it, size_t n) -> T* { - buffer<T>& buf = get_container(it); - auto size = buf.size(); - if (buf.capacity() < size + n) return nullptr; -@@ -401,192 +391,179 @@ template <typename T> T* to_pointer(buffer_appender<T> it, size_t n) { - } - - template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)> --inline std::back_insert_iterator<Container> base_iterator( -- std::back_insert_iterator<Container>& it, -- checked_ptr<typename Container::value_type>) { -+inline auto base_iterator(std::back_insert_iterator<Container>& it, -+ checked_ptr<typename Container::value_type>) -+ -> std::back_insert_iterator<Container> { - return it; - } - - template <typename Iterator> --inline Iterator base_iterator(Iterator, Iterator it) { -+constexpr auto base_iterator(Iterator, Iterator it) -> Iterator { - return it; - } - --// An output iterator that counts the number of objects written to it and --// discards them. --class counting_iterator { -- private: -- size_t count_; -- -- public: -- using iterator_category = std::output_iterator_tag; -- using difference_type = std::ptrdiff_t; -- using pointer = void; -- using reference = void; -- using _Unchecked_type = counting_iterator; // Mark iterator as checked. -- -- struct value_type { -- template <typename T> void operator=(const T&) {} -- }; -- -- counting_iterator() : count_(0) {} -- -- size_t count() const { return count_; } -- -- counting_iterator& operator++() { -- ++count_; -- return *this; -- } -- counting_iterator operator++(int) { -- auto it = *this; -- ++*this; -- return it; -- } -- -- friend counting_iterator operator+(counting_iterator it, difference_type n) { -- it.count_ += static_cast<size_t>(n); -- return it; -- } -- -- value_type operator*() const { return {}; } --}; -- --template <typename OutputIt> class truncating_iterator_base { -- protected: -- OutputIt out_; -- size_t limit_; -- size_t count_; -- -- truncating_iterator_base(OutputIt out, size_t limit) -- : out_(out), limit_(limit), count_(0) {} -- -- public: -- using iterator_category = std::output_iterator_tag; -- using value_type = typename std::iterator_traits<OutputIt>::value_type; -- using difference_type = void; -- using pointer = void; -- using reference = void; -- using _Unchecked_type = -- truncating_iterator_base; // Mark iterator as checked. -- -- OutputIt base() const { return out_; } -- size_t count() const { return count_; } --}; -- --// An output iterator that truncates the output and counts the number of objects --// written to it. --template <typename OutputIt, -- typename Enable = typename std::is_void< -- typename std::iterator_traits<OutputIt>::value_type>::type> --class truncating_iterator; -- --template <typename OutputIt> --class truncating_iterator<OutputIt, std::false_type> -- : public truncating_iterator_base<OutputIt> { -- mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_; -- -- public: -- using value_type = typename truncating_iterator_base<OutputIt>::value_type; -- -- truncating_iterator(OutputIt out, size_t limit) -- : truncating_iterator_base<OutputIt>(out, limit) {} -- -- truncating_iterator& operator++() { -- if (this->count_++ < this->limit_) ++this->out_; -- return *this; -+// <algorithm> is spectacularly slow to compile in C++20 so use a simple fill_n -+// instead (#1998). -+template <typename OutputIt, typename Size, typename T> -+FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T& value) -+ -> OutputIt { -+ for (Size i = 0; i < count; ++i) *out++ = value; -+ return out; -+} -+template <typename T, typename Size> -+FMT_CONSTEXPR20 auto fill_n(T* out, Size count, char value) -> T* { -+ if (is_constant_evaluated()) { -+ return fill_n<T*, Size, T>(out, count, value); - } -+ std::memset(out, value, to_unsigned(count)); -+ return out + count; -+} - -- truncating_iterator operator++(int) { -- auto it = *this; -- ++*this; -- return it; -- } -+#ifdef __cpp_char8_t -+using char8_type = char8_t; -+#else -+enum char8_type : unsigned char {}; -+#endif - -- value_type& operator*() const { -- return this->count_ < this->limit_ ? *this->out_ : blackhole_; -+template <typename OutChar, typename InputIt, typename OutputIt> -+FMT_CONSTEXPR FMT_NOINLINE auto copy_str_noinline(InputIt begin, InputIt end, -+ OutputIt out) -> OutputIt { -+ return copy_str<OutChar>(begin, end, out); -+} -+ -+// A public domain branchless UTF-8 decoder by Christopher Wellons: -+// https://github.com/skeeto/branchless-utf8 -+/* Decode the next character, c, from s, reporting errors in e. -+ * -+ * Since this is a branchless decoder, four bytes will be read from the -+ * buffer regardless of the actual length of the next character. This -+ * means the buffer _must_ have at least three bytes of zero padding -+ * following the end of the data stream. -+ * -+ * Errors are reported in e, which will be non-zero if the parsed -+ * character was somehow invalid: invalid byte sequence, non-canonical -+ * encoding, or a surrogate half. -+ * -+ * The function returns a pointer to the next character. When an error -+ * occurs, this pointer will be a guess that depends on the particular -+ * error, but it will always advance at least one byte. -+ */ -+FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e) -+ -> const char* { -+ constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07}; -+ constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536}; -+ constexpr const int shiftc[] = {0, 18, 12, 6, 0}; -+ constexpr const int shifte[] = {0, 6, 4, 2, 0}; -+ -+ int len = code_point_length(s); -+ const char* next = s + len; -+ -+ // Assume a four-byte character and load four bytes. Unused bits are -+ // shifted out. -+ *c = uint32_t(s[0] & masks[len]) << 18; -+ *c |= uint32_t(s[1] & 0x3f) << 12; -+ *c |= uint32_t(s[2] & 0x3f) << 6; -+ *c |= uint32_t(s[3] & 0x3f) << 0; -+ *c >>= shiftc[len]; -+ -+ // Accumulate the various error conditions. -+ using uchar = unsigned char; -+ *e = (*c < mins[len]) << 6; // non-canonical encoding -+ *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half? -+ *e |= (*c > 0x10FFFF) << 8; // out of range? -+ *e |= (uchar(s[1]) & 0xc0) >> 2; -+ *e |= (uchar(s[2]) & 0xc0) >> 4; -+ *e |= uchar(s[3]) >> 6; -+ *e ^= 0x2a; // top two bits of each tail byte correct? -+ *e >>= shifte[len]; -+ -+ return next; -+} -+ -+template <typename F> -+FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) { -+ auto decode = [f](const char* p) { -+ auto cp = uint32_t(); -+ auto error = 0; -+ p = utf8_decode(p, &cp, &error); -+ f(cp, error); -+ return p; -+ }; -+ auto p = s.data(); -+ const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. -+ if (s.size() >= block_size) { -+ for (auto end = p + s.size() - block_size + 1; p < end;) p = decode(p); - } --}; -- --template <typename OutputIt> --class truncating_iterator<OutputIt, std::true_type> -- : public truncating_iterator_base<OutputIt> { -- public: -- truncating_iterator(OutputIt out, size_t limit) -- : truncating_iterator_base<OutputIt>(out, limit) {} -- -- template <typename T> truncating_iterator& operator=(T val) { -- if (this->count_++ < this->limit_) *this->out_++ = val; -- return *this; -+ if (auto num_chars_left = s.data() + s.size() - p) { -+ char buf[2 * block_size - 1] = {}; -+ copy_str<char>(p, p + num_chars_left, buf); -+ p = buf; -+ do { -+ p = decode(p); -+ } while (p - buf < num_chars_left); - } -- -- truncating_iterator& operator++() { return *this; } -- truncating_iterator& operator++(int) { return *this; } -- truncating_iterator& operator*() { return *this; } --}; -+} - - template <typename Char> --inline size_t count_code_points(basic_string_view<Char> s) { -+inline auto compute_width(basic_string_view<Char> s) -> size_t { - return s.size(); - } - --// Counts the number of code points in a UTF-8 string. --inline size_t count_code_points(basic_string_view<char> s) { -- const char* data = s.data(); -+// Computes approximate display width of a UTF-8 string. -+FMT_CONSTEXPR inline size_t compute_width(string_view s) { - 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; -- } -+ // It is not a lambda for compatibility with C++14. -+ struct count_code_points { -+ size_t* count; -+ FMT_CONSTEXPR void operator()(uint32_t cp, int error) const { -+ *count += detail::to_unsigned( -+ 1 + -+ (error == 0 && cp >= 0x1100 && -+ (cp <= 0x115f || // Hangul Jamo init. consonants -+ cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET〈 -+ cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET 〉 -+ // CJK ... Yi except Unicode Character “〿”: -+ (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) || -+ (cp >= 0xac00 && cp <= 0xd7a3) || // Hangul Syllables -+ (cp >= 0xf900 && cp <= 0xfaff) || // CJK Compatibility Ideographs -+ (cp >= 0xfe10 && cp <= 0xfe19) || // Vertical Forms -+ (cp >= 0xfe30 && cp <= 0xfe6f) || // CJK Compatibility Forms -+ (cp >= 0xff00 && cp <= 0xff60) || // Fullwidth Forms -+ (cp >= 0xffe0 && cp <= 0xffe6) || // Fullwidth Forms -+ (cp >= 0x20000 && cp <= 0x2fffd) || // CJK -+ (cp >= 0x30000 && cp <= 0x3fffd) || -+ // Miscellaneous Symbols and Pictographs + Emoticons: -+ (cp >= 0x1f300 && cp <= 0x1f64f) || -+ // Supplemental Symbols and Pictographs: -+ (cp >= 0x1f900 && cp <= 0x1f9ff)))); -+ } -+ }; -+ for_each_codepoint(s, count_code_points{&num_code_points}); - return num_code_points; - } - --inline size_t count_code_points(basic_string_view<char8_type> s) { -- return count_code_points(basic_string_view<char>( -+inline auto compute_width(basic_string_view<char8_type> s) -> size_t { -+ return compute_width(basic_string_view<char>( - reinterpret_cast<const char*>(s.data()), s.size())); - } - - template <typename Char> --inline size_t code_point_index(basic_string_view<Char> s, size_t n) { -+inline auto code_point_index(basic_string_view<Char> s, size_t n) -> size_t { - size_t size = s.size(); - return n < size ? n : size; - } - - // Calculates the index of the nth code point in a UTF-8 string. --inline size_t code_point_index(basic_string_view<char8_type> s, size_t n) { -+inline auto code_point_index(basic_string_view<char8_type> s, size_t n) -+ -> size_t { - const char8_type* 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 > n) { -- return i; -- } -+ if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) return i; - } - return s.size(); - } - --template <typename InputIt, typename OutChar> --using needs_conversion = bool_constant< -- std::is_same<typename std::iterator_traits<InputIt>::value_type, -- char>::value && -- std::is_same<OutChar, char8_type>::value>; -- --template <typename OutChar, typename InputIt, typename OutputIt, -- FMT_ENABLE_IF(!needs_conversion<InputIt, OutChar>::value)> --OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) { -- return std::copy(begin, end, it); --} -- --template <typename OutChar, typename InputIt, typename OutputIt, -- FMT_ENABLE_IF(needs_conversion<InputIt, OutChar>::value)> --OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) { -- return std::transform(begin, end, it, -- [](char c) { return static_cast<char8_type>(c); }); --} -- --template <typename Char, typename InputIt> --inline counting_iterator copy_str(InputIt begin, InputIt end, -- counting_iterator it) { -- return it + (end - begin); --} -- - template <typename T> - using is_fast_float = bool_constant<std::numeric_limits<T>::is_iec559 && - sizeof(T) <= sizeof(double)>; -@@ -598,7 +575,7 @@ using is_fast_float = bool_constant<std::numeric_limits<T>::is_iec559 && - template <typename T> - template <typename U> - void buffer<T>::append(const U* begin, const U* end) { -- do { -+ while (begin != end) { - auto count = to_unsigned(end - begin); - try_reserve(size_ + count); - auto free_cap = capacity_ - size_; -@@ -606,16 +583,17 @@ void buffer<T>::append(const U* begin, const U* end) { - std::uninitialized_copy_n(begin, count, make_checked(ptr_ + size_, count)); - size_ += count; - begin += count; -- } while (begin != end); -+ } - } - --template <typename OutputIt, typename T, typename Traits> --void iterator_buffer<OutputIt, T, Traits>::flush() { -- out_ = std::copy_n(data_, this->limit(this->size()), out_); -- this->clear(); --} -+template <typename T, typename Enable = void> -+struct is_locale : std::false_type {}; -+template <typename T> -+struct is_locale<T, void_t<decltype(T::classic())>> : std::true_type {}; - } // namespace detail - -+FMT_MODULE_EXPORT_BEGIN -+ - // The number of characters to store in the basic_memory_buffer object itself - // to avoid dynamic memory allocation. - enum { inline_buffer_size = 500 }; -@@ -625,15 +603,7 @@ enum { inline_buffer_size = 500 }; - A dynamically growing memory buffer for trivially copyable/constructible types - with the first ``SIZE`` elements stored in the object itself. - -- You can use one of the following type aliases for common character types: -- -- +----------------+------------------------------+ -- | Type | Definition | -- +================+==============================+ -- | memory_buffer | basic_memory_buffer<char> | -- +----------------+------------------------------+ -- | wmemory_buffer | basic_memory_buffer<wchar_t> | -- +----------------+------------------------------+ -+ You can use the ```memory_buffer`` type alias for ``char`` instead. - - **Example**:: - -@@ -710,7 +680,8 @@ class basic_memory_buffer final : public detail::buffer<T> { - Moves the content of the other ``basic_memory_buffer`` object to this one. - \endrst - */ -- basic_memory_buffer& operator=(basic_memory_buffer&& other) FMT_NOEXCEPT { -+ auto operator=(basic_memory_buffer&& other) FMT_NOEXCEPT -+ -> basic_memory_buffer& { - FMT_ASSERT(this != &other, ""); - deallocate(); - move(other); -@@ -718,7 +689,7 @@ class basic_memory_buffer final : public detail::buffer<T> { - } - - // Returns a copy of the allocator associated with this buffer. -- Allocator get_allocator() const { return alloc_; } -+ auto get_allocator() const -> Allocator { return alloc_; } - - /** - Resizes the buffer to contain *count* elements. If T is a POD type new -@@ -742,9 +713,13 @@ void basic_memory_buffer<T, SIZE, Allocator>::grow(size_t size) { - #ifdef FMT_FUZZ - if (size > 5000) throw std::runtime_error("fuzz mode - won't grow that much"); - #endif -+ const size_t max_size = std::allocator_traits<Allocator>::max_size(alloc_); - size_t old_capacity = this->capacity(); - size_t new_capacity = old_capacity + old_capacity / 2; -- if (size > new_capacity) new_capacity = size; -+ if (size > new_capacity) -+ new_capacity = size; -+ else if (new_capacity > max_size) -+ new_capacity = size > max_size ? size : max_size; - T* old_data = this->data(); - T* new_data = - std::allocator_traits<Allocator>::allocate(alloc_, new_capacity); -@@ -759,12 +734,15 @@ void basic_memory_buffer<T, SIZE, Allocator>::grow(size_t size) { - } - - using memory_buffer = basic_memory_buffer<char>; --using wmemory_buffer = basic_memory_buffer<wchar_t>; - - template <typename T, size_t SIZE, typename Allocator> - struct is_contiguous<basic_memory_buffer<T, SIZE, Allocator>> : std::true_type { - }; - -+namespace detail { -+FMT_API void print(std::FILE*, string_view); -+} -+ - /** A formatting error such as invalid format string. */ - FMT_CLASS_API - class FMT_API format_error : public std::runtime_error { -@@ -776,10 +754,66 @@ class FMT_API format_error : public std::runtime_error { - format_error& operator=(const format_error&) = default; - format_error(format_error&&) = default; - format_error& operator=(format_error&&) = default; -- ~format_error() FMT_NOEXCEPT FMT_OVERRIDE; -+ ~format_error() FMT_NOEXCEPT FMT_OVERRIDE FMT_MSC_DEFAULT; - }; - --namespace detail { -+/** -+ \rst -+ Constructs a `~fmt::format_arg_store` object that contains references -+ to arguments and can be implicitly converted to `~fmt::format_args`. -+ If ``fmt`` is a compile-time string then `make_args_checked` checks -+ its validity at compile time. -+ \endrst -+ */ -+template <typename... Args, typename S, typename Char = char_t<S>> -+FMT_INLINE auto make_args_checked(const S& fmt, -+ const remove_reference_t<Args>&... args) -+ -> format_arg_store<buffer_context<Char>, remove_reference_t<Args>...> { -+ static_assert( -+ detail::count<( -+ std::is_base_of<detail::view, remove_reference_t<Args>>::value && -+ std::is_reference<Args>::value)...>() == 0, -+ "passing views as lvalues is disallowed"); -+ detail::check_format_string<Args...>(fmt); -+ return {args...}; -+} -+ -+// compile-time support -+namespace detail_exported { -+#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -+template <typename Char, size_t N> struct fixed_string { -+ constexpr fixed_string(const Char (&str)[N]) { -+ detail::copy_str<Char, const Char*, Char*>(static_cast<const Char*>(str), -+ str + N, data); -+ } -+ Char data[N]{}; -+}; -+#endif -+ -+// Converts a compile-time string to basic_string_view. -+template <typename Char, size_t N> -+constexpr auto compile_string_to_view(const Char (&s)[N]) -+ -> basic_string_view<Char> { -+ // Remove trailing NUL character if needed. Won't be present if this is used -+ // with a raw character array (i.e. not defined as a string). -+ return {s, N - (std::char_traits<Char>::to_int_type(s[N - 1]) == 0 ? 1 : 0)}; -+} -+template <typename Char> -+constexpr auto compile_string_to_view(detail::std_string_view<Char> s) -+ -> basic_string_view<Char> { -+ return {s.data(), s.size()}; -+} -+} // namespace detail_exported -+ -+FMT_BEGIN_DETAIL_NAMESPACE -+ -+inline void throw_format_error(const char* message) { -+ FMT_THROW(format_error(message)); -+} -+ -+template <typename T> struct is_integral : std::is_integral<T> {}; -+template <> struct is_integral<int128_t> : std::true_type {}; -+template <> struct is_integral<uint128_t> : std::true_type {}; - - template <typename T> - using is_signed = -@@ -789,16 +823,16 @@ using is_signed = - // Returns true if value is negative, false otherwise. - // Same as `value < 0` but doesn't produce warnings if T is an unsigned type. - template <typename T, FMT_ENABLE_IF(is_signed<T>::value)> --FMT_CONSTEXPR bool is_negative(T value) { -+FMT_CONSTEXPR auto is_negative(T value) -> bool { - return value < 0; - } - template <typename T, FMT_ENABLE_IF(!is_signed<T>::value)> --FMT_CONSTEXPR bool is_negative(T) { -+FMT_CONSTEXPR auto is_negative(T) -> bool { - return false; - } - - template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> --FMT_CONSTEXPR bool is_supported_floating_point(T) { -+FMT_CONSTEXPR auto is_supported_floating_point(T) -> uint16_t { - return (std::is_same<T, float>::value && FMT_USE_FLOAT) || - (std::is_same<T, double>::value && FMT_USE_DOUBLE) || - (std::is_same<T, long double>::value && FMT_USE_LONG_DOUBLE); -@@ -811,121 +845,56 @@ using uint32_or_64_or_128_t = - conditional_t<num_bits<T>() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS, - uint32_t, - conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>; -+template <typename T> -+using uint64_or_128_t = conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>; - --// 128-bit integer type used internally --struct FMT_EXTERN_TEMPLATE_API uint128_wrapper { -- uint128_wrapper() = default; -- --#if FMT_USE_INT128 -- uint128_t internal_; -- -- uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT -- : internal_{static_cast<uint128_t>(low) | -- (static_cast<uint128_t>(high) << 64)} {} -- -- uint128_wrapper(uint128_t u) : internal_{u} {} -- -- uint64_t high() const FMT_NOEXCEPT { return uint64_t(internal_ >> 64); } -- uint64_t low() const FMT_NOEXCEPT { return uint64_t(internal_); } -- -- uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT { -- internal_ += n; -- return *this; -- } --#else -- uint64_t high_; -- uint64_t low_; -- -- uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT : high_{high}, -- low_{low} {} -- -- uint64_t high() const FMT_NOEXCEPT { return high_; } -- uint64_t low() const FMT_NOEXCEPT { return low_; } -- -- uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT { --# if defined(_MSC_VER) && defined(_M_X64) -- unsigned char carry = _addcarry_u64(0, low_, n, &low_); -- _addcarry_u64(carry, high_, 0, &high_); -- return *this; --# else -- uint64_t sum = low_ + n; -- high_ += (sum < low_ ? 1 : 0); -- low_ = sum; -- return *this; --# endif -- } --#endif --}; -- --// Table entry type for divisibility test used internally --template <typename T> struct FMT_EXTERN_TEMPLATE_API divtest_table_entry { -- T mod_inv; -- T max_quotient; --}; -+#define FMT_POWERS_OF_10(factor) \ -+ factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \ -+ (factor)*1000000, (factor)*10000000, (factor)*100000000, \ -+ (factor)*1000000000 - - // Static data is placed in this class template for the header-only config. --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_new[]; -- static const uint64_t zero_or_powers_of_10_64_new[]; -- static const uint64_t grisu_pow10_significands[]; -- static const int16_t grisu_pow10_exponents[]; -- static const divtest_table_entry<uint32_t> divtest_table_for_pow5_32[]; -- static const divtest_table_entry<uint64_t> divtest_table_for_pow5_64[]; -- static const uint64_t dragonbox_pow10_significands_64[]; -- static const uint128_wrapper dragonbox_pow10_significands_128[]; -+template <typename T = void> struct basic_data { - // log10(2) = 0x0.4d104d427de7fbcc... - static const uint64_t log10_2_significand = 0x4d104d427de7fbcc; --#if !FMT_USE_FULL_CACHE_DRAGONBOX -- static const uint64_t powers_of_5_64[]; -- static const uint32_t dragonbox_pow10_recovery_errors[]; --#endif -+ - // GCC generates slightly better code for pairs than chars. -- using digit_pair = char[2]; -- static const digit_pair 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]; -- static const char signs[]; -- static const char left_padding_shifts[5]; -- static const char right_padding_shifts[5]; -- -- // DEPRECATED! These are for ABI compatibility. -- static const uint32_t zero_or_powers_of_10_32[]; -- static const uint64_t zero_or_powers_of_10_64[]; -+ FMT_API static constexpr const char digits[][2] = { -+ {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'}, -+ {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'}, -+ {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, -+ {'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, -+ {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'}, -+ {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'}, -+ {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'}, -+ {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'}, -+ {'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, -+ {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'}, -+ {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'}, -+ {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'}, -+ {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'}, -+ {'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, -+ {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'}, -+ {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'}, -+ {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}}; -+ -+ FMT_API static constexpr const char hex_digits[] = "0123456789abcdef"; -+ FMT_API static constexpr const char signs[] = {0, '-', '+', ' '}; -+ FMT_API static constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', -+ 0x1000000u | ' '}; -+ FMT_API static constexpr const char left_padding_shifts[] = {31, 31, 0, 1, 0}; -+ FMT_API static constexpr const char right_padding_shifts[] = {0, 31, 0, 1, 0}; - }; - --// Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). --// This is a function instead of an array to workaround a bug in GCC10 (#1810). --FMT_INLINE uint16_t bsr2log10(int bsr) { -- static constexpr uint16_t data[] = { -- 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, -- 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, -- 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, -- 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; -- return data[bsr]; --} -- --#ifndef FMT_EXPORTED --FMT_EXTERN template struct basic_data<void>; -+#ifdef FMT_SHARED -+// Required for -flto, -fivisibility=hidden and -shared to work -+extern template struct basic_data<void>; - #endif - - // This is a struct rather than an alias 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 --// except for n == 0 in which case count_digits returns 1. --inline int count_digits(uint64_t n) { -- // https://github.com/fmtlib/format-benchmark/blob/master/digits10 -- auto t = bsr2log10(FMT_BUILTIN_CLZLL(n | 1) ^ 63); -- return t - (n < data::zero_or_powers_of_10_64_new[t]); --} --#else --// Fallback version of count_digits used when __builtin_clz is not available. --inline int count_digits(uint64_t n) { -+template <typename T> FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { - int count = 1; - for (;;) { - // Integer division is slow so do it for a group of four digits instead -@@ -939,27 +908,41 @@ inline int count_digits(uint64_t n) { - count += 4; - } - } -+#if FMT_USE_INT128 -+FMT_CONSTEXPR inline auto count_digits(uint128_t n) -> int { -+ return count_digits_fallback(n); -+} - #endif - --#if FMT_USE_INT128 --inline int count_digits(uint128_t n) { -- int count = 1; -- for (;;) { -- // Integer division is slow so do it for a group of four digits instead -- // of for every digit. The idea comes from the talk by Alexandrescu -- // "Three Optimization Tips for C++". See speed-test for a comparison. -- if (n < 10) return count; -- if (n < 100) return count + 1; -- if (n < 1000) return count + 2; -- if (n < 10000) return count + 3; -- n /= 10000U; -- count += 4; -+// Returns the number of decimal digits in n. Leading zeros are not counted -+// except for n == 0 in which case count_digits returns 1. -+FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int { -+#ifdef FMT_BUILTIN_CLZLL -+ if (!is_constant_evaluated()) { -+ // https://github.com/fmtlib/format-benchmark/blob/master/digits10 -+ // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). -+ constexpr uint16_t bsr2log10[] = { -+ 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, -+ 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, -+ 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, -+ 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; -+ auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; -+ constexpr const uint64_t zero_or_powers_of_10[] = { -+ 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), -+ 10000000000000000000ULL}; -+ return t - (n < zero_or_powers_of_10[t]); - } --} - #endif -+ return count_digits_fallback(n); -+} - - // Counts the number of digits in n. BITS = log2(radix). --template <unsigned BITS, typename UInt> inline int count_digits(UInt n) { -+template <int BITS, typename UInt> -+FMT_CONSTEXPR auto count_digits(UInt n) -> int { -+#ifdef FMT_BUILTIN_CLZ -+ if (num_bits<UInt>() == 32) -+ return (FMT_BUILTIN_CLZ(static_cast<uint32_t>(n) | 1) ^ 31) / BITS + 1; -+#endif - int num_digits = 0; - do { - ++num_digits; -@@ -967,66 +950,82 @@ template <unsigned BITS, typename UInt> inline int count_digits(UInt n) { - return num_digits; - } - --template <> int count_digits<4>(detail::fallback_uintptr n); -- --#if FMT_GCC_VERSION || FMT_CLANG_VERSION --# define FMT_ALWAYS_INLINE inline __attribute__((always_inline)) --#elif FMT_MSC_VER --# define FMT_ALWAYS_INLINE __forceinline --#else --# define FMT_ALWAYS_INLINE inline --#endif -- --// To suppress unnecessary security cookie checks --#if FMT_MSC_VER && !FMT_CLANG_VERSION --# define FMT_SAFEBUFFERS __declspec(safebuffers) --#else --# define FMT_SAFEBUFFERS --#endif -+template <> auto count_digits<4>(detail::fallback_uintptr n) -> int; -+ -+// It is a separate function rather than a part of count_digits to workaround -+// the lack of static constexpr in constexpr functions. -+FMT_INLINE uint64_t count_digits_inc(int n) { -+ // An optimization by Kendall Willets from https://bit.ly/3uOIQrB. -+ // This increments the upper 32 bits (log10(T) - 1) when >= T is added. -+#define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T) -+ static constexpr uint64_t table[] = { -+ FMT_INC(0), FMT_INC(0), FMT_INC(0), // 8 -+ FMT_INC(10), FMT_INC(10), FMT_INC(10), // 64 -+ FMT_INC(100), FMT_INC(100), FMT_INC(100), // 512 -+ FMT_INC(1000), FMT_INC(1000), FMT_INC(1000), // 4096 -+ FMT_INC(10000), FMT_INC(10000), FMT_INC(10000), // 32k -+ FMT_INC(100000), FMT_INC(100000), FMT_INC(100000), // 256k -+ FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000), // 2048k -+ FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000), // 16M -+ FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000), // 128M -+ FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000), // 1024M -+ FMT_INC(1000000000), FMT_INC(1000000000) // 4B -+ }; -+ return table[n]; -+} - --#ifdef FMT_BUILTIN_CLZ - // Optional version of count_digits for better performance on 32-bit platforms. --inline int count_digits(uint32_t n) { -- auto t = bsr2log10(FMT_BUILTIN_CLZ(n | 1) ^ 31); -- return t - (n < data::zero_or_powers_of_10_32_new[t]); --} -+FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int { -+#ifdef FMT_BUILTIN_CLZ -+ if (!is_constant_evaluated()) { -+ auto inc = count_digits_inc(FMT_BUILTIN_CLZ(n | 1) ^ 31); -+ return static_cast<int>((n + inc) >> 32); -+ } - #endif -+ return count_digits_fallback(n); -+} - --template <typename Int> constexpr int digits10() FMT_NOEXCEPT { -+template <typename Int> constexpr auto digits10() FMT_NOEXCEPT -> int { - return std::numeric_limits<Int>::digits10; - } --template <> constexpr int digits10<int128_t>() FMT_NOEXCEPT { return 38; } --template <> constexpr int digits10<uint128_t>() FMT_NOEXCEPT { return 38; } -- --template <typename Char> FMT_API std::string grouping_impl(locale_ref loc); --template <typename Char> inline std::string grouping(locale_ref loc) { -- return grouping_impl<char>(loc); -+template <> constexpr auto digits10<int128_t>() FMT_NOEXCEPT -> int { -+ return 38; - } --template <> inline std::string grouping<wchar_t>(locale_ref loc) { -- return grouping_impl<wchar_t>(loc); -+template <> constexpr auto digits10<uint128_t>() FMT_NOEXCEPT -> int { -+ return 38; - } - --template <typename Char> FMT_API Char thousands_sep_impl(locale_ref loc); --template <typename Char> inline Char thousands_sep(locale_ref loc) { -- return Char(thousands_sep_impl<char>(loc)); -+template <typename Char> struct thousands_sep_result { -+ std::string grouping; -+ Char thousands_sep; -+}; -+ -+template <typename Char> -+FMT_API auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result<Char>; -+template <typename Char> -+inline auto thousands_sep(locale_ref loc) -> thousands_sep_result<Char> { -+ auto result = thousands_sep_impl<char>(loc); -+ return {result.grouping, Char(result.thousands_sep)}; - } --template <> inline wchar_t thousands_sep(locale_ref loc) { -+template <> -+inline auto thousands_sep(locale_ref loc) -> thousands_sep_result<wchar_t> { - return thousands_sep_impl<wchar_t>(loc); - } - --template <typename Char> FMT_API Char decimal_point_impl(locale_ref loc); --template <typename Char> inline Char decimal_point(locale_ref loc) { -+template <typename Char> -+FMT_API auto decimal_point_impl(locale_ref loc) -> Char; -+template <typename Char> inline auto decimal_point(locale_ref loc) -> Char { - return Char(decimal_point_impl<char>(loc)); - } --template <> inline wchar_t decimal_point(locale_ref loc) { -+template <> inline auto decimal_point(locale_ref loc) -> wchar_t { - return decimal_point_impl<wchar_t>(loc); - } - - // Compares two characters for equality. --template <typename Char> bool equal2(const Char* lhs, const char* rhs) { -+template <typename Char> auto equal2(const Char* lhs, const char* rhs) -> bool { - return lhs[0] == rhs[0] && lhs[1] == rhs[1]; - } --inline bool equal2(const char* lhs, const char* rhs) { -+inline auto equal2(const char* lhs, const char* rhs) -> bool { - return memcmp(lhs, rhs, 2) == 0; - } - -@@ -1046,11 +1045,19 @@ template <typename Iterator> struct format_decimal_result { - // buffer of specified size. The caller must ensure that the buffer is large - // enough. - template <typename Char, typename UInt> --inline format_decimal_result<Char*> format_decimal(Char* out, UInt value, -- int size) { -+FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size) -+ -> format_decimal_result<Char*> { - FMT_ASSERT(size >= count_digits(value), "invalid digit count"); - out += size; - Char* end = out; -+ if (is_constant_evaluated()) { -+ while (value >= 10) { -+ *--out = static_cast<Char>('0' + value % 10); -+ value /= 10; -+ } -+ *--out = static_cast<Char>('0' + value); -+ return {out, end}; -+ } - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu -@@ -1070,17 +1077,17 @@ inline format_decimal_result<Char*> format_decimal(Char* out, UInt value, - - template <typename Char, typename UInt, typename Iterator, - FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<Iterator>>::value)> --inline format_decimal_result<Iterator> format_decimal(Iterator out, UInt value, -- int size) { -+inline auto format_decimal(Iterator out, UInt value, int size) -+ -> format_decimal_result<Iterator> { - // Buffer is large enough to hold all digits (digits10 + 1). - Char buffer[digits10<UInt>() + 1]; - auto end = format_decimal(buffer, value, size).end; -- return {out, detail::copy_str<Char>(buffer, end, out)}; -+ return {out, detail::copy_str_noinline<Char>(buffer, end, out)}; - } - - template <unsigned BASE_BITS, typename Char, typename UInt> --inline Char* format_uint(Char* buffer, UInt value, int num_digits, -- bool upper = false) { -+FMT_CONSTEXPR auto format_uint(Char* buffer, UInt value, int num_digits, -+ bool upper = false) -> Char* { - buffer += num_digits; - Char* end = buffer; - do { -@@ -1093,8 +1100,8 @@ inline Char* format_uint(Char* buffer, UInt value, int num_digits, - } - - template <unsigned BASE_BITS, typename Char> --Char* format_uint(Char* buffer, detail::fallback_uintptr n, int num_digits, -- bool = false) { -+auto format_uint(Char* buffer, detail::fallback_uintptr n, int num_digits, -+ bool = false) -> Char* { - 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) { -@@ -1115,7 +1122,8 @@ Char* format_uint(Char* buffer, detail::fallback_uintptr n, int num_digits, - } - - template <unsigned BASE_BITS, typename Char, typename It, typename UInt> --inline It format_uint(It out, UInt value, int num_digits, bool upper = false) { -+inline auto format_uint(It out, UInt value, int num_digits, bool upper = false) -+ -> It { - if (auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) { - format_uint<BASE_BITS>(ptr, value, num_digits, upper); - return out; -@@ -1123,86 +1131,22 @@ 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). - char buffer[num_bits<UInt>() / BASE_BITS + 1]; - format_uint<BASE_BITS>(buffer, value, num_digits, upper); -- return detail::copy_str<Char>(buffer, buffer + num_digits, out); -+ return detail::copy_str_noinline<Char>(buffer, buffer + num_digits, out); - } - - // A converter from UTF-8 to UTF-16. - class utf8_to_utf16 { - private: -- wmemory_buffer buffer_; -+ basic_memory_buffer<wchar_t> buffer_; - - public: - FMT_API explicit utf8_to_utf16(string_view s); -- operator wstring_view() const { return {&buffer_[0], size()}; } -- size_t size() const { return buffer_.size() - 1; } -- const wchar_t* c_str() const { return &buffer_[0]; } -- std::wstring str() const { return {&buffer_[0], size()}; } --}; -- --template <typename T = void> struct null {}; -- --// Workaround an array initialization issue in gcc 4.8. --template <typename Char> struct fill_t { -- private: -- enum { max_size = 4 }; -- Char data_[max_size] = {Char(' '), Char(0), Char(0), Char(0)}; -- unsigned char size_ = 1; -- -- public: -- FMT_CONSTEXPR void operator=(basic_string_view<Char> s) { -- auto size = s.size(); -- if (size > max_size) { -- FMT_THROW(format_error("invalid fill")); -- return; -- } -- for (size_t i = 0; i < size; ++i) data_[i] = s[i]; -- size_ = static_cast<unsigned char>(size); -- } -- -- size_t size() const { return size_; } -- const Char* data() const { return data_; } -- -- FMT_CONSTEXPR Char& operator[](size_t index) { return data_[index]; } -- FMT_CONSTEXPR const Char& operator[](size_t index) const { -- return data_[index]; -- } -+ operator basic_string_view<wchar_t>() const { return {&buffer_[0], size()}; } -+ auto size() const -> size_t { return buffer_.size() - 1; } -+ auto c_str() const -> const wchar_t* { return &buffer_[0]; } -+ auto str() const -> std::wstring { return {&buffer_[0], size()}; } - }; --} // namespace detail -- --// We cannot use enum classes as bit fields because of a gcc bug --// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414. --namespace align { --enum type { none, left, right, center, numeric }; --} --using align_t = align::type; -- --namespace sign { --enum type { none, minus, plus, space }; --} --using sign_t = sign::type; -- --// Format specifiers for built-in and string types. --template <typename Char> struct basic_format_specs { -- int width; -- int precision; -- char type; -- align_t align : 4; -- sign_t sign : 3; -- bool alt : 1; // Alternate form ('#'). -- detail::fill_t<Char> fill; -- -- constexpr basic_format_specs() -- : width(0), -- precision(-1), -- type(0), -- align(align::none), -- sign(sign::none), -- alt(false) {} --}; -- --using format_specs = basic_format_specs<char>; - --namespace detail { - namespace dragonbox { - - // Type-specific information that Dragonbox uses. -@@ -1266,37 +1210,21 @@ template <typename T> struct decimal_fp { - int exponent; - }; - --template <typename T> FMT_API decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT; -+template <typename T> -+FMT_API auto to_decimal(T x) FMT_NOEXCEPT -> decimal_fp<T>; - } // namespace dragonbox - - template <typename T> --constexpr typename dragonbox::float_info<T>::carrier_uint exponent_mask() { -+constexpr auto exponent_mask() -> -+ typename dragonbox::float_info<T>::carrier_uint { - using uint = typename dragonbox::float_info<T>::carrier_uint; - return ((uint(1) << dragonbox::float_info<T>::exponent_bits) - 1) - << dragonbox::float_info<T>::significand_bits; - } - --// A floating-point presentation format. --enum class float_format : unsigned char { -- general, // General: exponent notation or fixed point based on magnitude. -- exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3. -- fixed, // Fixed point with the default precision of 6, e.g. 0.0012. -- hex --}; -- --struct float_specs { -- int precision; -- float_format format : 8; -- sign_t sign : 8; -- bool upper : 1; -- bool locale : 1; -- bool binary32 : 1; -- bool use_grisu : 1; -- bool showpoint : 1; --}; -- - // Writes the exponent exp in the form "[+-]d{2,3}" to buffer. --template <typename Char, typename It> It write_exponent(int exp, It it) { -+template <typename Char, typename It> -+auto write_exponent(int exp, It it) -> It { - FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range"); - if (exp < 0) { - *it++ = static_cast<Char>('-'); -@@ -1317,174 +1245,28 @@ template <typename Char, typename It> It write_exponent(int exp, It it) { - } - - template <typename T> --int format_float(T value, int precision, float_specs specs, buffer<char>& buf); -+auto format_float(T value, int precision, float_specs specs, buffer<char>& buf) -+ -> int; - - // Formats a floating-point number with snprintf. - template <typename T> --int snprintf_float(T value, int precision, float_specs specs, -- buffer<char>& buf); -+auto snprintf_float(T value, int precision, float_specs specs, -+ buffer<char>& buf) -> int; - --template <typename T> T promote_float(T value) { return value; } --inline double promote_float(float value) { return static_cast<double>(value); } -- --template <typename Handler> --FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) { -- switch (spec) { -- case 0: -- case 'd': -- handler.on_dec(); -- break; -- case 'x': -- case 'X': -- handler.on_hex(); -- break; -- case 'b': -- case 'B': -- handler.on_bin(); -- break; -- case 'o': -- handler.on_oct(); -- break; --#ifdef FMT_DEPRECATED_N_SPECIFIER -- case 'n': --#endif -- case 'L': -- handler.on_num(); -- break; -- case 'c': -- handler.on_chr(); -- break; -- default: -- handler.on_error(); -- } -+template <typename T> auto promote_float(T value) -> T { return value; } -+inline auto promote_float(float value) -> double { -+ return static_cast<double>(value); - } - --template <typename ErrorHandler = error_handler, typename Char> --FMT_CONSTEXPR float_specs parse_float_type_spec( -- const basic_format_specs<Char>& specs, ErrorHandler&& eh = {}) { -- auto result = float_specs(); -- result.showpoint = specs.alt; -- switch (specs.type) { -- case 0: -- result.format = float_format::general; -- result.showpoint |= specs.precision > 0; -- break; -- case 'G': -- result.upper = true; -- FMT_FALLTHROUGH; -- case 'g': -- result.format = float_format::general; -- break; -- case 'E': -- result.upper = true; -- FMT_FALLTHROUGH; -- case 'e': -- result.format = float_format::exp; -- result.showpoint |= specs.precision != 0; -- break; -- case 'F': -- result.upper = true; -- FMT_FALLTHROUGH; -- case 'f': -- result.format = float_format::fixed; -- result.showpoint |= specs.precision != 0; -- break; -- case 'A': -- result.upper = true; -- FMT_FALLTHROUGH; -- case 'a': -- result.format = float_format::hex; -- break; --#ifdef FMT_DEPRECATED_N_SPECIFIER -- case 'n': --#endif -- case 'L': -- result.locale = true; -- break; -- default: -- eh.on_error("invalid type specifier"); -- break; -- } -- return result; --} -- --template <typename Char, typename Handler> --FMT_CONSTEXPR void handle_char_specs(const basic_format_specs<Char>* specs, -- Handler&& handler) { -- if (!specs) return handler.on_char(); -- if (specs->type && specs->type != 'c') return handler.on_int(); -- if (specs->align == align::numeric || specs->sign != sign::none || specs->alt) -- handler.on_error("invalid format specifier for char"); -- handler.on_char(); --} -- --template <typename Char, typename Handler> --FMT_CONSTEXPR void handle_cstring_type_spec(Char spec, Handler&& handler) { -- if (spec == 0 || spec == 's') -- handler.on_string(); -- else if (spec == 'p') -- handler.on_pointer(); -- else -- handler.on_error("invalid type specifier"); --} -- --template <typename Char, typename ErrorHandler> --FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler&& eh) { -- if (spec != 0 && spec != 's') eh.on_error("invalid type specifier"); --} -- --template <typename Char, typename ErrorHandler> --FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) { -- if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier"); --} -- --template <typename ErrorHandler> class int_type_checker : private ErrorHandler { -- public: -- FMT_CONSTEXPR explicit int_type_checker(ErrorHandler eh) : ErrorHandler(eh) {} -- -- FMT_CONSTEXPR void on_dec() {} -- FMT_CONSTEXPR void on_hex() {} -- FMT_CONSTEXPR void on_bin() {} -- FMT_CONSTEXPR void on_oct() {} -- FMT_CONSTEXPR void on_num() {} -- FMT_CONSTEXPR void on_chr() {} -- -- FMT_CONSTEXPR void on_error() { -- ErrorHandler::on_error("invalid type specifier"); -- } --}; -- --template <typename ErrorHandler> --class char_specs_checker : public ErrorHandler { -- private: -- char type_; -- -- public: -- FMT_CONSTEXPR char_specs_checker(char type, ErrorHandler eh) -- : ErrorHandler(eh), type_(type) {} -- -- FMT_CONSTEXPR void on_int() { -- handle_int_type_spec(type_, int_type_checker<ErrorHandler>(*this)); -- } -- FMT_CONSTEXPR void on_char() {} --}; -- --template <typename ErrorHandler> --class cstring_type_checker : public ErrorHandler { -- public: -- FMT_CONSTEXPR explicit cstring_type_checker(ErrorHandler eh) -- : ErrorHandler(eh) {} -- -- FMT_CONSTEXPR void on_string() {} -- FMT_CONSTEXPR void on_pointer() {} --}; -- --template <typename OutputIt, typename Char> --FMT_NOINLINE OutputIt fill(OutputIt it, size_t n, const fill_t<Char>& fill) { -- auto fill_size = fill.size(); -- if (fill_size == 1) return std::fill_n(it, n, fill[0]); -- for (size_t i = 0; i < n; ++i) it = std::copy_n(fill.data(), fill_size, it); -- return it; -+template <typename OutputIt, typename Char> -+FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, -+ const fill_t<Char>& fill) -> OutputIt { -+ auto fill_size = fill.size(); -+ if (fill_size == 1) return detail::fill_n(it, n, fill[0]); -+ auto data = fill.data(); -+ for (size_t i = 0; i < n; ++i) -+ it = copy_str<Char>(data, data + fill_size, it); -+ return it; - } - - // Writes the output of f, padded according to format specifications in specs. -@@ -1492,39 +1274,72 @@ FMT_NOINLINE OutputIt fill(OutputIt it, size_t n, const fill_t<Char>& fill) { - // width: output display width in (terminal) column positions. - template <align::type align = align::left, typename OutputIt, typename Char, - typename F> --inline OutputIt write_padded(OutputIt out, -- const basic_format_specs<Char>& specs, size_t size, -- size_t width, F&& f) { -+FMT_CONSTEXPR auto write_padded(OutputIt out, -+ const basic_format_specs<Char>& specs, -+ size_t size, size_t width, F&& f) -> OutputIt { - static_assert(align == align::left || align == align::right, ""); - unsigned spec_width = to_unsigned(specs.width); - size_t padding = spec_width > width ? spec_width - width : 0; - auto* shifts = align == align::left ? data::left_padding_shifts - : data::right_padding_shifts; - size_t left_padding = padding >> shifts[specs.align]; -+ size_t right_padding = padding - left_padding; - auto it = reserve(out, size + padding * specs.fill.size()); -- it = fill(it, left_padding, specs.fill); -+ if (left_padding != 0) it = fill(it, left_padding, specs.fill); - it = f(it); -- it = fill(it, padding - left_padding, specs.fill); -+ if (right_padding != 0) it = fill(it, right_padding, specs.fill); - return base_iterator(out, it); - } - - template <align::type align = align::left, typename OutputIt, typename Char, - typename F> --inline OutputIt write_padded(OutputIt out, -- const basic_format_specs<Char>& specs, size_t size, -- F&& f) { -+constexpr auto write_padded(OutputIt out, const basic_format_specs<Char>& specs, -+ size_t size, F&& f) -> OutputIt { - return write_padded<align>(out, specs, size, size, f); - } - -+template <align::type align = align::left, typename Char, typename OutputIt> -+FMT_CONSTEXPR auto write_bytes(OutputIt out, string_view bytes, -+ const basic_format_specs<Char>& specs) -+ -> OutputIt { -+ return write_padded<align>( -+ out, specs, bytes.size(), [bytes](reserve_iterator<OutputIt> it) { -+ const char* data = bytes.data(); -+ return copy_str<Char>(data, data + bytes.size(), it); -+ }); -+} -+ -+template <typename Char, typename OutputIt, typename UIntPtr> -+auto write_ptr(OutputIt out, UIntPtr value, -+ const basic_format_specs<Char>* specs) -> OutputIt { -+ int num_digits = count_digits<4>(value); -+ auto size = to_unsigned(num_digits) + size_t(2); -+ auto write = [=](reserve_iterator<OutputIt> it) { -+ *it++ = static_cast<Char>('0'); -+ *it++ = static_cast<Char>('x'); -+ return format_uint<4, Char>(it, value, num_digits); -+ }; -+ return specs ? write_padded<align::right>(out, *specs, size, write) -+ : base_iterator(out, write(reserve(out, size))); -+} -+ - template <typename Char, typename OutputIt> --OutputIt write_bytes(OutputIt out, string_view bytes, -- const basic_format_specs<Char>& specs) { -- using iterator = remove_reference_t<decltype(reserve(out, 0))>; -- return write_padded(out, specs, bytes.size(), [bytes](iterator it) { -- const char* data = bytes.data(); -- return copy_str<Char>(data, data + bytes.size(), it); -+FMT_CONSTEXPR auto write_char(OutputIt out, Char value, -+ const basic_format_specs<Char>& specs) -+ -> OutputIt { -+ return write_padded(out, specs, 1, [=](reserve_iterator<OutputIt> it) { -+ *it++ = value; -+ return it; - }); - } -+template <typename Char, typename OutputIt> -+FMT_CONSTEXPR auto write(OutputIt out, Char value, -+ const basic_format_specs<Char>& specs, -+ locale_ref loc = {}) -> OutputIt { -+ return check_char_specs(specs) -+ ? write_char(out, value, specs) -+ : write(out, static_cast<int>(value), specs, loc); -+} - - // Data for write_int that doesn't depend on output iterator type. It is used to - // avoid template code bloat. -@@ -1532,9 +1347,9 @@ template <typename Char> struct write_int_data { - size_t size; - size_t padding; - -- write_int_data(int num_digits, string_view prefix, -- const basic_format_specs<Char>& specs) -- : size(prefix.size() + to_unsigned(num_digits)), padding(0) { -+ FMT_CONSTEXPR write_int_data(int num_digits, unsigned prefix, -+ const basic_format_specs<Char>& specs) -+ : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) { - if (specs.align == align::numeric) { - auto width = to_unsigned(specs.width); - if (width > size) { -@@ -1542,7 +1357,7 @@ template <typename Char> struct write_int_data { - size = width; - } - } else if (specs.precision > num_digits) { -- size = prefix.size() + to_unsigned(specs.precision); -+ size = (prefix >> 24) + to_unsigned(specs.precision); - padding = to_unsigned(specs.precision - num_digits); - } - } -@@ -1550,182 +1365,232 @@ template <typename Char> struct write_int_data { - - // Writes an integer in the format - // <left-padding><prefix><numeric-padding><digits><right-padding> --// where <digits> are written by f(it). --template <typename OutputIt, typename Char, typename F> --OutputIt write_int(OutputIt out, int num_digits, string_view prefix, -- const basic_format_specs<Char>& specs, F f) { -+// where <digits> are written by write_digits(it). -+// prefix contains chars in three lower bytes and the size in the fourth byte. -+template <typename OutputIt, typename Char, typename W> -+FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits, -+ unsigned prefix, -+ const basic_format_specs<Char>& specs, -+ W write_digits) -> OutputIt { -+ // Slightly faster check for specs.width == 0 && specs.precision == -1. -+ if ((specs.width | (specs.precision + 1)) == 0) { -+ auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24)); -+ if (prefix != 0) { -+ for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) -+ *it++ = static_cast<Char>(p & 0xff); -+ } -+ return base_iterator(out, write_digits(it)); -+ } - auto data = write_int_data<Char>(num_digits, prefix, specs); -- using iterator = remove_reference_t<decltype(reserve(out, 0))>; -- return write_padded<align::right>(out, specs, data.size, [=](iterator it) { -- if (prefix.size() != 0) -- it = copy_str<Char>(prefix.begin(), prefix.end(), it); -- it = std::fill_n(it, data.padding, static_cast<Char>('0')); -- return f(it); -- }); -+ return write_padded<align::right>( -+ out, specs, data.size, [=](reserve_iterator<OutputIt> it) { -+ for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) -+ *it++ = static_cast<Char>(p & 0xff); -+ it = detail::fill_n(it, data.padding, static_cast<Char>('0')); -+ return write_digits(it); -+ }); -+} -+ -+template <typename OutputIt, typename UInt, typename Char> -+auto write_int_localized(OutputIt& out, UInt value, unsigned prefix, -+ const basic_format_specs<Char>& specs, locale_ref loc) -+ -> bool { -+ static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value, ""); -+ const auto sep_size = 1; -+ auto ts = thousands_sep<Char>(loc); -+ if (!ts.thousands_sep) return false; -+ int num_digits = count_digits(value); -+ int size = num_digits, n = num_digits; -+ const std::string& groups = ts.grouping; -+ std::string::const_iterator group = groups.cbegin(); -+ while (group != groups.cend() && n > *group && *group > 0 && -+ *group != max_value<char>()) { -+ size += sep_size; -+ n -= *group; -+ ++group; -+ } -+ if (group == groups.cend()) size += sep_size * ((n - 1) / groups.back()); -+ char digits[40]; -+ format_decimal(digits, value, num_digits); -+ basic_memory_buffer<Char> buffer; -+ if (prefix != 0) ++size; -+ const auto usize = to_unsigned(size); -+ buffer.resize(usize); -+ basic_string_view<Char> s(&ts.thousands_sep, sep_size); -+ // Index of a decimal digit with the least significant digit having index 0. -+ int digit_index = 0; -+ group = groups.cbegin(); -+ auto p = buffer.data() + size - 1; -+ for (int i = num_digits - 1; i > 0; --i) { -+ *p-- = static_cast<Char>(digits[i]); -+ if (*group <= 0 || ++digit_index % *group != 0 || -+ *group == max_value<char>()) -+ continue; -+ if (group + 1 != groups.cend()) { -+ digit_index = 0; -+ ++group; -+ } -+ std::uninitialized_copy(s.data(), s.data() + s.size(), -+ make_checked(p, s.size())); -+ p -= s.size(); -+ } -+ *p-- = static_cast<Char>(*digits); -+ if (prefix != 0) *p = static_cast<Char>(prefix); -+ auto data = buffer.data(); -+ out = write_padded<align::right>( -+ out, specs, usize, usize, [=](reserve_iterator<OutputIt> it) { -+ return copy_str<Char>(data, data + size, it); -+ }); -+ return true; - } - --template <typename StrChar, typename Char, typename OutputIt> --OutputIt write(OutputIt out, basic_string_view<StrChar> s, -- const basic_format_specs<Char>& specs) { -- auto data = s.data(); -- auto size = s.size(); -- if (specs.precision >= 0 && to_unsigned(specs.precision) < size) -- size = code_point_index(s, to_unsigned(specs.precision)); -- auto width = specs.width != 0 -- ? count_code_points(basic_string_view<StrChar>(data, size)) -- : 0; -- using iterator = remove_reference_t<decltype(reserve(out, 0))>; -- return write_padded(out, specs, size, width, [=](iterator it) { -- return copy_str<Char>(data, data + size, it); -- }); -+FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) { -+ prefix |= prefix != 0 ? value << 8 : value; -+ prefix += (1u + (value > 0xff ? 1 : 0)) << 24; - } - --// The handle_int_type_spec handler that writes an integer. --template <typename OutputIt, typename Char, typename UInt> struct int_writer { -- OutputIt out; -- locale_ref locale; -- const basic_format_specs<Char>& specs; -+template <typename UInt> struct write_int_arg { - UInt abs_value; -- char prefix[4]; -- unsigned prefix_size; -- -- using iterator = -- remove_reference_t<decltype(reserve(std::declval<OutputIt&>(), 0))>; -- -- string_view get_prefix() const { return string_view(prefix, prefix_size); } -- -- template <typename Int> -- int_writer(OutputIt output, locale_ref loc, Int value, -- const basic_format_specs<Char>& s) -- : out(output), -- locale(loc), -- specs(s), -- abs_value(static_cast<UInt>(value)), -- prefix_size(0) { -- static_assert(std::is_same<uint32_or_64_or_128_t<Int>, UInt>::value, ""); -- if (is_negative(value)) { -- prefix[0] = '-'; -- ++prefix_size; -- abs_value = 0 - abs_value; -- } else if (specs.sign != sign::none && specs.sign != sign::minus) { -- prefix[0] = specs.sign == sign::plus ? '+' : ' '; -- ++prefix_size; -- } -+ unsigned prefix; -+}; -+ -+template <typename T> -+FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign) -+ -> write_int_arg<uint32_or_64_or_128_t<T>> { -+ auto prefix = 0u; -+ auto abs_value = static_cast<uint32_or_64_or_128_t<T>>(value); -+ if (is_negative(value)) { -+ prefix = 0x01000000 | '-'; -+ abs_value = 0 - abs_value; -+ } else { -+ prefix = data::prefixes[sign]; - } -+ return {abs_value, prefix}; -+} - -- void on_dec() { -+template <typename Char, typename OutputIt, typename T> -+FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg<T> arg, -+ const basic_format_specs<Char>& specs, -+ locale_ref loc) -> OutputIt { -+ static_assert(std::is_same<T, uint32_or_64_or_128_t<T>>::value, ""); -+ auto abs_value = arg.abs_value; -+ auto prefix = arg.prefix; -+ auto utype = static_cast<unsigned>(specs.type); -+ switch (specs.type) { -+ case 0: -+ case 'd': { -+ if (specs.localized && -+ write_int_localized(out, static_cast<uint64_or_128_t<T>>(abs_value), -+ prefix, specs, loc)) { -+ return out; -+ } - auto num_digits = count_digits(abs_value); -- out = write_int( -- out, num_digits, get_prefix(), specs, [this, num_digits](iterator it) { -+ return write_int( -+ out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) { - return format_decimal<Char>(it, abs_value, num_digits).end; - }); - } -- -- void on_hex() { -- if (specs.alt) { -- prefix[prefix_size++] = '0'; -- prefix[prefix_size++] = specs.type; -- } -+ case 'x': -+ case 'X': { -+ if (specs.alt) prefix_append(prefix, (utype << 8) | '0'); -+ bool upper = specs.type != 'x'; - int num_digits = count_digits<4>(abs_value); -- out = write_int(out, num_digits, get_prefix(), specs, -- [this, num_digits](iterator it) { -- return format_uint<4, Char>(it, abs_value, num_digits, -- specs.type != 'x'); -- }); -+ return write_int( -+ out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) { -+ return format_uint<4, Char>(it, abs_value, num_digits, upper); -+ }); - } -- -- void on_bin() { -- if (specs.alt) { -- prefix[prefix_size++] = '0'; -- prefix[prefix_size++] = static_cast<char>(specs.type); -- } -+ case 'b': -+ case 'B': { -+ if (specs.alt) prefix_append(prefix, (utype << 8) | '0'); - int num_digits = count_digits<1>(abs_value); -- out = write_int(out, num_digits, get_prefix(), specs, -- [this, num_digits](iterator it) { -- return format_uint<1, Char>(it, abs_value, num_digits); -- }); -+ return write_int(out, num_digits, prefix, specs, -+ [=](reserve_iterator<OutputIt> it) { -+ return format_uint<1, Char>(it, abs_value, num_digits); -+ }); - } -- -- void on_oct() { -+ case 'o': { - int num_digits = count_digits<3>(abs_value); - if (specs.alt && specs.precision <= num_digits && abs_value != 0) { - // Octal prefix '0' is counted as a digit, so only add it if precision - // is not greater than the number of digits. -- prefix[prefix_size++] = '0'; -- } -- out = write_int(out, num_digits, get_prefix(), specs, -- [this, num_digits](iterator it) { -- return format_uint<3, Char>(it, abs_value, num_digits); -- }); -- } -- -- enum { sep_size = 1 }; -- -- void on_num() { -- std::string groups = grouping<Char>(locale); -- if (groups.empty()) return on_dec(); -- auto sep = thousands_sep<Char>(locale); -- if (!sep) return on_dec(); -- int num_digits = count_digits(abs_value); -- int size = num_digits, n = num_digits; -- std::string::const_iterator group = groups.cbegin(); -- while (group != groups.cend() && n > *group && *group > 0 && -- *group != max_value<char>()) { -- size += sep_size; -- n -= *group; -- ++group; -- } -- if (group == groups.cend()) size += sep_size * ((n - 1) / groups.back()); -- char digits[40]; -- format_decimal(digits, abs_value, num_digits); -- basic_memory_buffer<Char> buffer; -- size += static_cast<int>(prefix_size); -- const auto usize = to_unsigned(size); -- buffer.resize(usize); -- basic_string_view<Char> s(&sep, sep_size); -- // Index of a decimal digit with the least significant digit having index 0. -- int digit_index = 0; -- group = groups.cbegin(); -- auto p = buffer.data() + size - 1; -- for (int i = num_digits - 1; i > 0; --i) { -- *p-- = static_cast<Char>(digits[i]); -- if (*group <= 0 || ++digit_index % *group != 0 || -- *group == max_value<char>()) -- continue; -- if (group + 1 != groups.cend()) { -- digit_index = 0; -- ++group; -- } -- std::uninitialized_copy(s.data(), s.data() + s.size(), -- make_checked(p, s.size())); -- p -= s.size(); -+ prefix_append(prefix, '0'); - } -- *p-- = static_cast<Char>(*digits); -- if (prefix_size != 0) *p = static_cast<Char>('-'); -- auto data = buffer.data(); -- out = write_padded<align::right>( -- out, specs, usize, usize, -- [=](iterator it) { return copy_str<Char>(data, data + size, it); }); -+ return write_int(out, num_digits, prefix, specs, -+ [=](reserve_iterator<OutputIt> it) { -+ return format_uint<3, Char>(it, abs_value, num_digits); -+ }); - } -- -- void on_chr() { *out++ = static_cast<Char>(abs_value); } -- -- FMT_NORETURN void on_error() { -+ case 'c': -+ return write_char(out, static_cast<Char>(abs_value), specs); -+ default: - FMT_THROW(format_error("invalid type specifier")); - } --}; -+ return out; -+} -+template <typename Char, typename OutputIt, typename T, -+ FMT_ENABLE_IF(is_integral<T>::value && -+ !std::is_same<T, bool>::value && -+ std::is_same<OutputIt, buffer_appender<Char>>::value)> -+FMT_CONSTEXPR auto write(OutputIt out, T value, -+ const basic_format_specs<Char>& specs, locale_ref loc) -+ -> OutputIt { -+ return write_int(out, make_write_int_arg(value, specs.sign), specs, loc); -+} -+// An inlined version of write used in format string compilation. -+template <typename Char, typename OutputIt, typename T, -+ FMT_ENABLE_IF(is_integral<T>::value && -+ !std::is_same<T, bool>::value && -+ !std::is_same<OutputIt, buffer_appender<Char>>::value)> -+FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, -+ const basic_format_specs<Char>& specs, -+ locale_ref loc) -> OutputIt { -+ return write_int(out, make_write_int_arg(value, specs.sign), specs, loc); -+} - - template <typename Char, typename OutputIt> --OutputIt write_nonfinite(OutputIt out, bool isinf, -- const basic_format_specs<Char>& specs, -- const float_specs& fspecs) { -+FMT_CONSTEXPR auto write(OutputIt out, basic_string_view<Char> s, -+ const basic_format_specs<Char>& specs) -> OutputIt { -+ auto data = s.data(); -+ auto size = s.size(); -+ if (specs.precision >= 0 && to_unsigned(specs.precision) < size) -+ size = code_point_index(s, to_unsigned(specs.precision)); -+ auto width = -+ specs.width != 0 ? compute_width(basic_string_view<Char>(data, size)) : 0; -+ return write_padded(out, specs, size, width, -+ [=](reserve_iterator<OutputIt> it) { -+ return copy_str<Char>(data, data + size, it); -+ }); -+} -+template <typename Char, typename OutputIt> -+FMT_CONSTEXPR auto write(OutputIt out, -+ basic_string_view<type_identity_t<Char>> s, -+ const basic_format_specs<Char>& specs, locale_ref) -+ -> OutputIt { -+ return write(out, s, specs); -+} -+template <typename Char, typename OutputIt> -+FMT_CONSTEXPR auto write(OutputIt out, const Char* s, -+ const basic_format_specs<Char>& specs, locale_ref) -+ -> OutputIt { -+ return check_cstring_type_spec(specs.type) -+ ? write(out, basic_string_view<Char>(s), specs, {}) -+ : write_ptr<Char>(out, to_uintptr(s), &specs); -+} -+ -+template <typename Char, typename OutputIt> -+auto write_nonfinite(OutputIt out, bool isinf, basic_format_specs<Char> specs, -+ const float_specs& fspecs) -> OutputIt { - auto str = - isinf ? (fspecs.upper ? "INF" : "inf") : (fspecs.upper ? "NAN" : "nan"); - constexpr size_t str_size = 3; - auto sign = fspecs.sign; - auto size = str_size + (sign ? 1 : 0); -- using iterator = remove_reference_t<decltype(reserve(out, 0))>; -- return write_padded(out, specs, size, [=](iterator it) { -+ // Replace '0'-padding with space for non-finite values. -+ const bool is_zero_fill = -+ specs.fill.size() == 1 && *specs.fill.data() == static_cast<Char>('0'); -+ if (is_zero_fill) specs.fill[0] = static_cast<Char>(' '); -+ return write_padded(out, specs, size, [=](reserve_iterator<OutputIt> it) { - if (sign) *it++ = static_cast<Char>(data::signs[sign]); - return copy_str<Char>(str, str + str_size, it); - }); -@@ -1738,74 +1603,76 @@ struct big_decimal_fp { - int exponent; - }; - --inline int get_significand_size(const big_decimal_fp& fp) { -+inline auto get_significand_size(const big_decimal_fp& fp) -> int { - return fp.significand_size; - } - template <typename T> --inline int get_significand_size(const dragonbox::decimal_fp<T>& fp) { -+inline auto get_significand_size(const dragonbox::decimal_fp<T>& fp) -> int { - return count_digits(fp.significand); - } - - template <typename Char, typename OutputIt> --inline OutputIt write_significand(OutputIt out, const char* significand, -- int& significand_size) { -+inline auto write_significand(OutputIt out, const char* significand, -+ int& significand_size) -> OutputIt { - return copy_str<Char>(significand, significand + significand_size, out); - } - template <typename Char, typename OutputIt, typename UInt> --inline OutputIt write_significand(OutputIt out, UInt significand, -- int significand_size) { -+inline auto write_significand(OutputIt out, UInt significand, -+ int significand_size) -> OutputIt { - return format_decimal<Char>(out, significand, significand_size).end; - } - - template <typename Char, typename UInt, - FMT_ENABLE_IF(std::is_integral<UInt>::value)> --inline Char* write_significand(Char* out, UInt significand, -- int significand_size, int integral_size, -- Char decimal_point) { -+inline auto write_significand(Char* out, UInt significand, int significand_size, -+ int integral_size, Char decimal_point) -> Char* { - if (!decimal_point) - return format_decimal(out, significand, significand_size).end; - auto end = format_decimal(out + 1, significand, significand_size).end; -- if (integral_size == 1) -+ if (integral_size == 1) { - out[0] = out[1]; -- else -- std::copy_n(out + 1, integral_size, out); -+ } else { -+ std::uninitialized_copy_n(out + 1, integral_size, -+ make_checked(out, to_unsigned(integral_size))); -+ } - out[integral_size] = decimal_point; - return end; - } - - template <typename OutputIt, typename UInt, typename Char, - FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)> --inline OutputIt write_significand(OutputIt out, UInt significand, -- int significand_size, int integral_size, -- Char decimal_point) { -+inline auto write_significand(OutputIt out, UInt significand, -+ int significand_size, int integral_size, -+ Char decimal_point) -> OutputIt { - // Buffer is large enough to hold digits (digits10 + 1) and a decimal point. - Char buffer[digits10<UInt>() + 2]; - auto end = write_significand(buffer, significand, significand_size, - integral_size, decimal_point); -- return detail::copy_str<Char>(buffer, end, out); -+ return detail::copy_str_noinline<Char>(buffer, end, out); - } - - template <typename OutputIt, typename Char> --inline OutputIt write_significand(OutputIt out, const char* significand, -- int significand_size, int integral_size, -- Char decimal_point) { -- out = detail::copy_str<Char>(significand, significand + integral_size, out); -+inline auto write_significand(OutputIt out, const char* significand, -+ int significand_size, int integral_size, -+ Char decimal_point) -> OutputIt { -+ out = detail::copy_str_noinline<Char>(significand, -+ significand + integral_size, out); - if (!decimal_point) return out; - *out++ = decimal_point; -- return detail::copy_str<Char>(significand + integral_size, -- significand + significand_size, out); -+ return detail::copy_str_noinline<Char>(significand + integral_size, -+ significand + significand_size, out); - } - - template <typename OutputIt, typename DecimalFP, typename Char> --OutputIt write_float(OutputIt out, const DecimalFP& fp, -- const basic_format_specs<Char>& specs, float_specs fspecs, -- Char decimal_point) { -+auto write_float(OutputIt out, const DecimalFP& fp, -+ const basic_format_specs<Char>& specs, float_specs fspecs, -+ Char decimal_point) -> OutputIt { - auto significand = fp.significand; - int significand_size = get_significand_size(fp); - static const Char zero = static_cast<Char>('0'); - auto sign = fspecs.sign; - size_t size = to_unsigned(significand_size) + (sign ? 1 : 0); -- using iterator = remove_reference_t<decltype(reserve(out, 0))>; -+ using iterator = reserve_iterator<OutputIt>; - - int output_exp = fp.exponent + significand_size - 1; - auto use_exp_format = [=]() { -@@ -1820,7 +1687,8 @@ OutputIt write_float(OutputIt out, const DecimalFP& fp, - if (use_exp_format()) { - int num_zeros = 0; - if (fspecs.showpoint) { -- num_zeros = (std::max)(fspecs.precision - significand_size, 0); -+ num_zeros = fspecs.precision - significand_size; -+ if (num_zeros < 0) num_zeros = 0; - size += to_unsigned(num_zeros); - } else if (significand_size == 1) { - decimal_point = Char(); -@@ -1836,7 +1704,7 @@ OutputIt write_float(OutputIt out, const DecimalFP& fp, - // Insert a decimal point after the first digit and add an exponent. - it = write_significand(it, significand, significand_size, 1, - decimal_point); -- if (num_zeros > 0) it = std::fill_n(it, num_zeros, zero); -+ if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero); - *it++ = static_cast<Char>(exp_char); - return write_exponent<Char>(output_exp, it); - }; -@@ -1855,15 +1723,15 @@ OutputIt write_float(OutputIt out, const DecimalFP& fp, - #endif - if (fspecs.showpoint) { - if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 1; -- if (num_zeros > 0) size += to_unsigned(num_zeros); -+ if (num_zeros > 0) size += to_unsigned(num_zeros) + 1; - } - return write_padded<align::right>(out, specs, size, [&](iterator it) { - if (sign) *it++ = static_cast<Char>(data::signs[sign]); - it = write_significand<Char>(it, significand, significand_size); -- it = std::fill_n(it, fp.exponent, zero); -+ it = detail::fill_n(it, fp.exponent, zero); - if (!fspecs.showpoint) return it; - *it++ = decimal_point; -- return num_zeros > 0 ? std::fill_n(it, num_zeros, zero) : it; -+ return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; - }); - } else if (exp > 0) { - // 1234e-2 -> 12.34[0+] -@@ -1873,7 +1741,7 @@ OutputIt write_float(OutputIt out, const DecimalFP& fp, - if (sign) *it++ = static_cast<Char>(data::signs[sign]); - it = write_significand(it, significand, significand_size, exp, - decimal_point); -- return num_zeros > 0 ? std::fill_n(it, num_zeros, zero) : it; -+ return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; - }); - } - // 1234e-6 -> 0.001234 -@@ -1882,21 +1750,22 @@ OutputIt write_float(OutputIt out, const DecimalFP& fp, - fspecs.precision < num_zeros) { - num_zeros = fspecs.precision; - } -- size += 2 + to_unsigned(num_zeros); -+ bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint; -+ size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros); - return write_padded<align::right>(out, specs, size, [&](iterator it) { - if (sign) *it++ = static_cast<Char>(data::signs[sign]); - *it++ = zero; -- if (num_zeros == 0 && significand_size == 0 && !fspecs.showpoint) return it; -+ if (!pointy) return it; - *it++ = decimal_point; -- it = std::fill_n(it, num_zeros, zero); -+ it = detail::fill_n(it, num_zeros, zero); - return write_significand<Char>(it, significand, significand_size); - }); - } - - template <typename Char, typename OutputIt, typename T, - FMT_ENABLE_IF(std::is_floating_point<T>::value)> --OutputIt write(OutputIt out, T value, basic_format_specs<Char> specs, -- locale_ref loc = {}) { -+auto write(OutputIt out, T value, basic_format_specs<Char> specs, -+ locale_ref loc = {}) -> OutputIt { - if (const_check(!is_supported_floating_point(value))) return out; - float_specs fspecs = parse_float_type_spec(specs); - fspecs.sign = specs.sign; -@@ -1922,7 +1791,8 @@ OutputIt write(OutputIt out, T value, basic_format_specs<Char> specs, - if (fspecs.format == float_format::hex) { - if (fspecs.sign) buffer.push_back(data::signs[fspecs.sign]); - snprintf_float(promote_float(value), specs.precision, fspecs, buffer); -- return write_bytes(out, {buffer.data(), buffer.size()}, specs); -+ return write_bytes<align::right>(out, {buffer.data(), buffer.size()}, -+ specs); - } - int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6; - if (fspecs.format == float_format::exp) { -@@ -1943,7 +1813,7 @@ OutputIt write(OutputIt out, T value, basic_format_specs<Char> specs, - - template <typename Char, typename OutputIt, typename T, - FMT_ENABLE_IF(is_fast_float<T>::value)> --OutputIt write(OutputIt out, T value) { -+auto write(OutputIt out, T value) -> OutputIt { - if (const_check(!is_supported_floating_point(value))) return out; - - using floaty = conditional_t<std::is_same<T, long double>::value, double, T>; -@@ -1969,72 +1839,36 @@ OutputIt write(OutputIt out, T value) { - template <typename Char, typename OutputIt, typename T, - FMT_ENABLE_IF(std::is_floating_point<T>::value && - !is_fast_float<T>::value)> --inline OutputIt write(OutputIt out, T value) { -+inline auto write(OutputIt out, T value) -> OutputIt { - return write(out, value, basic_format_specs<Char>()); - } - - template <typename Char, typename OutputIt> --OutputIt write_char(OutputIt out, Char value, -- const basic_format_specs<Char>& specs) { -- using iterator = remove_reference_t<decltype(reserve(out, 0))>; -- return write_padded(out, specs, 1, [=](iterator it) { -- *it++ = value; -- return it; -- }); --} -- --template <typename Char, typename OutputIt, typename UIntPtr> --OutputIt write_ptr(OutputIt out, UIntPtr value, -- const basic_format_specs<Char>* specs) { -- int num_digits = count_digits<4>(value); -- auto size = to_unsigned(num_digits) + size_t(2); -- using iterator = remove_reference_t<decltype(reserve(out, 0))>; -- auto write = [=](iterator it) { -- *it++ = static_cast<Char>('0'); -- *it++ = static_cast<Char>('x'); -- return format_uint<4, Char>(it, value, num_digits); -- }; -- return specs ? write_padded<align::right>(out, *specs, size, write) -- : base_iterator(out, write(reserve(out, size))); --} -- --template <typename T> struct is_integral : std::is_integral<T> {}; --template <> struct is_integral<int128_t> : std::true_type {}; --template <> struct is_integral<uint128_t> : std::true_type {}; -- --template <typename Char, typename OutputIt> --OutputIt write(OutputIt out, monostate) { -+auto write(OutputIt out, monostate, basic_format_specs<Char> = {}, -+ locale_ref = {}) -> OutputIt { - FMT_ASSERT(false, ""); - return out; - } - --template <typename Char, typename OutputIt, -- FMT_ENABLE_IF(!std::is_same<Char, char>::value)> --OutputIt write(OutputIt out, string_view value) { -- auto it = reserve(out, value.size()); -- it = copy_str<Char>(value.begin(), value.end(), it); -- return base_iterator(out, it); --} -- - template <typename Char, typename OutputIt> --OutputIt write(OutputIt out, basic_string_view<Char> value) { -+FMT_CONSTEXPR auto write(OutputIt out, basic_string_view<Char> value) -+ -> OutputIt { - auto it = reserve(out, value.size()); -- it = std::copy(value.begin(), value.end(), it); -+ it = copy_str_noinline<Char>(value.begin(), value.end(), it); - return base_iterator(out, it); - } - --template <typename Char> --buffer_appender<Char> write(buffer_appender<Char> out, -- basic_string_view<Char> value) { -- get_container(out).append(value.begin(), value.end()); -- return out; -+template <typename Char, typename OutputIt, typename T, -+ FMT_ENABLE_IF(is_string<T>::value)> -+constexpr auto write(OutputIt out, const T& value) -> OutputIt { -+ return write<Char>(out, to_string_view(value)); - } - - template <typename Char, typename OutputIt, typename T, - FMT_ENABLE_IF(is_integral<T>::value && - !std::is_same<T, bool>::value && - !std::is_same<T, Char>::value)> --OutputIt write(OutputIt out, T value) { -+FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { - auto abs_value = static_cast<uint32_or_64_or_128_t<T>>(value); - bool negative = is_negative(value); - // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer. -@@ -2052,20 +1886,39 @@ OutputIt write(OutputIt out, T value) { - return base_iterator(out, it); - } - --template <typename Char, typename OutputIt> --OutputIt write(OutputIt out, bool value) { -- return write<Char>(out, string_view(value ? "true" : "false")); -+// FMT_ENABLE_IF() condition separated to workaround MSVC bug -+template < -+ typename Char, typename OutputIt, typename T, -+ bool check = -+ std::is_enum<T>::value && !std::is_same<T, Char>::value && -+ mapped_type_constant<T, basic_format_context<OutputIt, Char>>::value != -+ type::custom_type, -+ FMT_ENABLE_IF(check)> -+FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { -+ return write<Char>( -+ out, static_cast<typename std::underlying_type<T>::type>(value)); -+} -+ -+template <typename Char, typename OutputIt, typename T, -+ FMT_ENABLE_IF(std::is_same<T, bool>::value)> -+FMT_CONSTEXPR auto write(OutputIt out, T value, -+ const basic_format_specs<Char>& specs = {}, -+ locale_ref = {}) -> OutputIt { -+ return specs.type && specs.type != 's' -+ ? write(out, value ? 1 : 0, specs, {}) -+ : write_bytes(out, value ? "true" : "false", specs); - } - - template <typename Char, typename OutputIt> --OutputIt write(OutputIt out, Char value) { -+FMT_CONSTEXPR auto write(OutputIt out, Char value) -> OutputIt { - auto it = reserve(out, 1); - *it++ = value; - return base_iterator(out, it); - } - - template <typename Char, typename OutputIt> --OutputIt write(OutputIt out, const Char* value) { -+FMT_CONSTEXPR_CHAR_TRAITS auto write(OutputIt out, const Char* value) -+ -> OutputIt { - if (!value) { - FMT_THROW(format_error("string pointer is null")); - } else { -@@ -2075,16 +1928,21 @@ OutputIt write(OutputIt out, const Char* value) { - return out; - } - --template <typename Char, typename OutputIt> --OutputIt write(OutputIt out, const void* value) { -- return write_ptr<Char>(out, to_uintptr(value), nullptr); -+template <typename Char, typename OutputIt, typename T, -+ FMT_ENABLE_IF(std::is_same<T, void>::value)> -+auto write(OutputIt out, const T* value, -+ const basic_format_specs<Char>& specs = {}, locale_ref = {}) -+ -> OutputIt { -+ check_pointer_type_spec(specs.type, error_handler()); -+ return write_ptr<Char>(out, to_uintptr(value), &specs); - } - - template <typename Char, typename OutputIt, typename T> --auto write(OutputIt out, const T& value) -> typename std::enable_if< -- mapped_type_constant<T, basic_format_context<OutputIt, Char>>::value == -- type::custom_type, -- OutputIt>::type { -+FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> -+ typename std::enable_if< -+ mapped_type_constant<T, basic_format_context<OutputIt, Char>>::value == -+ type::custom_type, -+ OutputIt>::type { - using context_type = basic_format_context<OutputIt, Char>; - using formatter_type = - conditional_t<has_formatter<T, context_type>::value, -@@ -2096,292 +1954,52 @@ auto write(OutputIt out, const T& value) -> typename std::enable_if< - - // An argument visitor that formats the argument and writes it via the output - // iterator. It's a class and not a generic lambda for compatibility with C++11. --template <typename OutputIt, typename Char> struct default_arg_formatter { -- using context = basic_format_context<OutputIt, Char>; -+template <typename Char> struct default_arg_formatter { -+ using iterator = buffer_appender<Char>; -+ using context = buffer_context<Char>; - -- OutputIt out; -+ iterator out; - basic_format_args<context> args; - locale_ref loc; - -- template <typename T> OutputIt operator()(T value) { -+ template <typename T> auto operator()(T value) -> iterator { - return write<Char>(out, value); - } -- -- OutputIt operator()(typename basic_format_arg<context>::handle handle) { -+ auto operator()(typename basic_format_arg<context>::handle h) -> iterator { - basic_format_parse_context<Char> parse_ctx({}); -- basic_format_context<OutputIt, Char> format_ctx(out, args, loc); -- handle.format(parse_ctx, format_ctx); -+ context format_ctx(out, args, loc); -+ h.format(parse_ctx, format_ctx); - return format_ctx.out(); - } - }; - --template <typename OutputIt, typename Char, -- typename ErrorHandler = error_handler> --class arg_formatter_base { -- public: -- using iterator = OutputIt; -- using char_type = Char; -- using format_specs = basic_format_specs<Char>; -- -- private: -- iterator out_; -- locale_ref locale_; -- format_specs* specs_; -- -- // Attempts to reserve space for n extra characters in the output range. -- // Returns a pointer to the reserved range or a reference to out_. -- auto reserve(size_t n) -> decltype(detail::reserve(out_, n)) { -- return detail::reserve(out_, n); -- } -- -- using reserve_iterator = remove_reference_t<decltype( -- detail::reserve(std::declval<iterator&>(), 0))>; -- -- template <typename T> void write_int(T value, const format_specs& spec) { -- using uint_type = uint32_or_64_or_128_t<T>; -- int_writer<iterator, Char, uint_type> w(out_, locale_, value, spec); -- handle_int_type_spec(spec.type, w); -- out_ = w.out; -- } -- -- void write(char value) { -- auto&& it = reserve(1); -- *it++ = value; -- } -- -- template <typename Ch, FMT_ENABLE_IF(std::is_same<Ch, Char>::value)> -- void write(Ch value) { -- out_ = detail::write<Char>(out_, value); -- } -- -- void write(string_view value) { -- auto&& it = reserve(value.size()); -- it = copy_str<Char>(value.begin(), value.end(), it); -- } -- void write(wstring_view value) { -- static_assert(std::is_same<Char, wchar_t>::value, ""); -- auto&& it = reserve(value.size()); -- it = std::copy(value.begin(), value.end(), it); -- } -- -- template <typename Ch> -- void write(const Ch* s, size_t size, const format_specs& specs) { -- auto width = specs.width != 0 -- ? count_code_points(basic_string_view<Ch>(s, size)) -- : 0; -- out_ = write_padded(out_, specs, size, width, [=](reserve_iterator it) { -- return copy_str<Char>(s, s + size, it); -- }); -- } -- -- template <typename Ch> -- void write(basic_string_view<Ch> s, const format_specs& specs = {}) { -- out_ = detail::write(out_, s, specs); -- } -- -- void write_pointer(const void* p) { -- out_ = write_ptr<char_type>(out_, to_uintptr(p), specs_); -- } -- -- struct char_spec_handler : ErrorHandler { -- arg_formatter_base& formatter; -- Char value; -- -- char_spec_handler(arg_formatter_base& f, Char val) -- : formatter(f), value(val) {} -- -- void on_int() { -- // char is only formatted as int if there are specs. -- formatter.write_int(static_cast<int>(value), *formatter.specs_); -- } -- void on_char() { -- if (formatter.specs_) -- formatter.out_ = write_char(formatter.out_, value, *formatter.specs_); -- else -- formatter.write(value); -- } -- }; -- -- struct cstring_spec_handler : error_handler { -- arg_formatter_base& formatter; -- const Char* value; -- -- cstring_spec_handler(arg_formatter_base& f, const Char* val) -- : formatter(f), value(val) {} -- -- void on_string() { formatter.write(value); } -- void on_pointer() { formatter.write_pointer(value); } -- }; -- -- protected: -- iterator out() { return out_; } -- format_specs* specs() { return specs_; } -- -- void write(bool value) { -- if (specs_) -- write(string_view(value ? "true" : "false"), *specs_); -- else -- out_ = detail::write<Char>(out_, value); -- } -- -- void write(const Char* value) { -- if (!value) { -- FMT_THROW(format_error("string pointer is null")); -- } else { -- auto length = std::char_traits<char_type>::length(value); -- basic_string_view<char_type> sv(value, length); -- specs_ ? write(sv, *specs_) : write(sv); -- } -- } -- -- public: -- arg_formatter_base(OutputIt out, format_specs* s, locale_ref loc) -- : out_(out), locale_(loc), specs_(s) {} -- -- iterator operator()(monostate) { -- FMT_ASSERT(false, "invalid argument type"); -- return out_; -- } -- -- template <typename T, FMT_ENABLE_IF(is_integral<T>::value)> -- FMT_INLINE iterator operator()(T value) { -- if (specs_) -- write_int(value, *specs_); -- else -- out_ = detail::write<Char>(out_, value); -- return out_; -- } -- -- iterator operator()(Char value) { -- handle_char_specs(specs_, -- char_spec_handler(*this, static_cast<Char>(value))); -- return out_; -- } -+template <typename Char> struct arg_formatter { -+ using iterator = buffer_appender<Char>; -+ using context = buffer_context<Char>; - -- iterator operator()(bool value) { -- if (specs_ && specs_->type) return (*this)(value ? 1 : 0); -- write(value != 0); -- return out_; -- } -- -- template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> -- iterator operator()(T value) { -- auto specs = specs_ ? *specs_ : format_specs(); -- if (const_check(is_supported_floating_point(value))) -- out_ = detail::write(out_, value, specs, locale_); -- else -- FMT_ASSERT(false, "unsupported float argument type"); -- return out_; -- } -- -- iterator operator()(const Char* value) { -- if (!specs_) return write(value), out_; -- handle_cstring_type_spec(specs_->type, cstring_spec_handler(*this, value)); -- return out_; -- } -- -- iterator operator()(basic_string_view<Char> value) { -- if (specs_) { -- check_string_type_spec(specs_->type, error_handler()); -- write(value, *specs_); -- } else { -- write(value); -- } -- return out_; -- } -+ iterator out; -+ const basic_format_specs<Char>& specs; -+ locale_ref locale; - -- iterator operator()(const void* value) { -- if (specs_) check_pointer_type_spec(specs_->type, error_handler()); -- write_pointer(value); -- return out_; -+ template <typename T> -+ FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator { -+ return detail::write(out, value, specs, locale); - } --}; -- --/** The default argument formatter. */ --template <typename OutputIt, typename Char> --class arg_formatter : public arg_formatter_base<OutputIt, Char> { -- private: -- using char_type = Char; -- using base = arg_formatter_base<OutputIt, Char>; -- using context_type = basic_format_context<OutputIt, Char>; -- -- context_type& ctx_; -- basic_format_parse_context<char_type>* parse_ctx_; -- const Char* ptr_; -- -- public: -- using iterator = typename base::iterator; -- using format_specs = typename base::format_specs; -- -- /** -- \rst -- Constructs an argument formatter object. -- *ctx* is a reference to the formatting context, -- *specs* contains format specifier information for standard argument types. -- \endrst -- */ -- explicit arg_formatter( -- context_type& ctx, -- basic_format_parse_context<char_type>* parse_ctx = nullptr, -- format_specs* specs = nullptr, const Char* ptr = nullptr) -- : base(ctx.out(), specs, ctx.locale()), -- ctx_(ctx), -- parse_ctx_(parse_ctx), -- ptr_(ptr) {} -- -- using base::operator(); -- -- /** Formats an argument of a user-defined type. */ -- iterator operator()(typename basic_format_arg<context_type>::handle handle) { -- if (ptr_) advance_to(*parse_ctx_, ptr_); -- handle.format(*parse_ctx_, ctx_); -- return ctx_.out(); -+ auto operator()(typename basic_format_arg<context>::handle) -> iterator { -+ // User-defined types are handled separately because they require access -+ // to the parse context. -+ return out; - } - }; - --template <typename Char> FMT_CONSTEXPR bool is_name_start(Char c) { -- return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; --} -- --// Parses the range [begin, end) as an unsigned integer. This function assumes --// that the range is non-empty and the first character is a digit. --template <typename Char, typename ErrorHandler> --FMT_CONSTEXPR int parse_nonnegative_int(const Char*& begin, const Char* end, -- ErrorHandler&& eh) { -- FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', ""); -- unsigned value = 0; -- // Convert to unsigned to prevent a warning. -- constexpr unsigned max_int = max_value<int>(); -- unsigned big = max_int / 10; -- do { -- // Check for overflow. -- if (value > big) { -- value = max_int + 1; -- break; -- } -- value = value * 10 + unsigned(*begin - '0'); -- ++begin; -- } while (begin != end && '0' <= *begin && *begin <= '9'); -- if (value > max_int) eh.on_error("number is too big"); -- return static_cast<int>(value); --} -- --template <typename Context> class custom_formatter { -- private: -- using char_type = typename Context::char_type; -- -- basic_format_parse_context<char_type>& parse_ctx_; -- Context& ctx_; -- -- public: -- explicit custom_formatter(basic_format_parse_context<char_type>& parse_ctx, -- Context& ctx) -- : parse_ctx_(parse_ctx), ctx_(ctx) {} -+template <typename Char> struct custom_formatter { -+ basic_format_parse_context<Char>& parse_ctx; -+ buffer_context<Char>& ctx; - -- void operator()(typename basic_format_arg<Context>::handle h) const { -- h.format(parse_ctx_, ctx_); -+ void operator()( -+ typename basic_format_arg<buffer_context<Char>>::handle h) const { -+ h.format(parse_ctx, ctx); - } -- - template <typename T> void operator()(T) const {} - }; - -@@ -2396,13 +2014,13 @@ template <typename ErrorHandler> class width_checker { - explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {} - - template <typename T, FMT_ENABLE_IF(is_integer<T>::value)> -- FMT_CONSTEXPR unsigned long long operator()(T value) { -+ FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { - if (is_negative(value)) handler_.on_error("negative width"); - return static_cast<unsigned long long>(value); - } - - template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)> -- FMT_CONSTEXPR unsigned long long operator()(T) { -+ FMT_CONSTEXPR auto operator()(T) -> unsigned long long { - handler_.on_error("width is not integer"); - return 0; - } -@@ -2416,13 +2034,13 @@ template <typename ErrorHandler> class precision_checker { - explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {} - - template <typename T, FMT_ENABLE_IF(is_integer<T>::value)> -- FMT_CONSTEXPR unsigned long long operator()(T value) { -+ FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { - if (is_negative(value)) handler_.on_error("negative precision"); - return static_cast<unsigned long long>(value); - } - - template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)> -- FMT_CONSTEXPR unsigned long long operator()(T) { -+ FMT_CONSTEXPR auto operator()(T) -> unsigned long long { - handler_.on_error("precision is not integer"); - return 0; - } -@@ -2431,148 +2049,50 @@ template <typename ErrorHandler> class precision_checker { - ErrorHandler& handler_; - }; - --// A format specifier handler that sets fields in basic_format_specs. --template <typename Char> class specs_setter { -- public: -- explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char>& specs) -- : specs_(specs) {} -+template <template <typename> class Handler, typename FormatArg, -+ typename ErrorHandler> -+FMT_CONSTEXPR auto get_dynamic_spec(FormatArg arg, ErrorHandler eh) -> int { -+ unsigned long long value = visit_format_arg(Handler<ErrorHandler>(eh), arg); -+ if (value > to_unsigned(max_value<int>())) eh.on_error("number is too big"); -+ return static_cast<int>(value); -+} - -- FMT_CONSTEXPR specs_setter(const specs_setter& other) -- : specs_(other.specs_) {} -+template <typename Context, typename ID> -+FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> -+ typename Context::format_arg { -+ auto arg = ctx.arg(id); -+ if (!arg) ctx.on_error("argument not found"); -+ return arg; -+} - -- FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; } -- FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) { -- specs_.fill = fill; -- } -- FMT_CONSTEXPR void on_plus() { specs_.sign = sign::plus; } -- FMT_CONSTEXPR void on_minus() { specs_.sign = sign::minus; } -- FMT_CONSTEXPR void on_space() { specs_.sign = sign::space; } -- FMT_CONSTEXPR void on_hash() { specs_.alt = true; } -+// The standard format specifier handler with checking. -+template <typename Char> class specs_handler : public specs_setter<Char> { -+ private: -+ basic_format_parse_context<Char>& parse_context_; -+ buffer_context<Char>& context_; - -- FMT_CONSTEXPR void on_zero() { -- specs_.align = align::numeric; -- specs_.fill[0] = Char('0'); -- } -+ // This is only needed for compatibility with gcc 4.4. -+ using format_arg = basic_format_arg<buffer_context<Char>>; - -- FMT_CONSTEXPR void on_width(int width) { specs_.width = width; } -- FMT_CONSTEXPR void on_precision(int precision) { -- specs_.precision = precision; -+ FMT_CONSTEXPR auto get_arg(auto_id) -> format_arg { -+ return detail::get_arg(context_, parse_context_.next_arg_id()); - } -- FMT_CONSTEXPR void end_precision() {} - -- FMT_CONSTEXPR void on_type(Char type) { -- specs_.type = static_cast<char>(type); -- } -- -- protected: -- basic_format_specs<Char>& specs_; --}; -- --template <typename ErrorHandler> class numeric_specs_checker { -- public: -- FMT_CONSTEXPR numeric_specs_checker(ErrorHandler& eh, detail::type arg_type) -- : error_handler_(eh), arg_type_(arg_type) {} -- -- FMT_CONSTEXPR void require_numeric_argument() { -- if (!is_arithmetic_type(arg_type_)) -- error_handler_.on_error("format specifier requires numeric argument"); -- } -- -- FMT_CONSTEXPR void check_sign() { -- require_numeric_argument(); -- if (is_integral_type(arg_type_) && arg_type_ != type::int_type && -- arg_type_ != type::long_long_type && arg_type_ != type::char_type) { -- error_handler_.on_error("format specifier requires signed argument"); -- } -- } -- -- FMT_CONSTEXPR void check_precision() { -- if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type) -- error_handler_.on_error("precision not allowed for this argument type"); -- } -- -- private: -- ErrorHandler& error_handler_; -- detail::type arg_type_; --}; -- --// A format specifier handler that checks if specifiers are consistent with the --// argument type. --template <typename Handler> class specs_checker : public Handler { -- private: -- numeric_specs_checker<Handler> checker_; -- -- // Suppress an MSVC warning about using this in initializer list. -- FMT_CONSTEXPR Handler& error_handler() { return *this; } -- -- public: -- FMT_CONSTEXPR specs_checker(const Handler& handler, detail::type arg_type) -- : Handler(handler), checker_(error_handler(), arg_type) {} -- -- FMT_CONSTEXPR specs_checker(const specs_checker& other) -- : Handler(other), checker_(error_handler(), other.arg_type_) {} -- -- FMT_CONSTEXPR void on_align(align_t align) { -- if (align == align::numeric) checker_.require_numeric_argument(); -- Handler::on_align(align); -- } -- -- FMT_CONSTEXPR void on_plus() { -- checker_.check_sign(); -- Handler::on_plus(); -- } -- -- FMT_CONSTEXPR void on_minus() { -- checker_.check_sign(); -- Handler::on_minus(); -- } -- -- FMT_CONSTEXPR void on_space() { -- checker_.check_sign(); -- Handler::on_space(); -- } -- -- FMT_CONSTEXPR void on_hash() { -- checker_.require_numeric_argument(); -- Handler::on_hash(); -+ FMT_CONSTEXPR auto get_arg(int arg_id) -> format_arg { -+ parse_context_.check_arg_id(arg_id); -+ return detail::get_arg(context_, arg_id); - } - -- FMT_CONSTEXPR void on_zero() { -- checker_.require_numeric_argument(); -- Handler::on_zero(); -+ FMT_CONSTEXPR auto get_arg(basic_string_view<Char> arg_id) -> format_arg { -+ parse_context_.check_arg_id(arg_id); -+ return detail::get_arg(context_, arg_id); - } - -- FMT_CONSTEXPR void end_precision() { checker_.check_precision(); } --}; -- --template <template <typename> class Handler, typename FormatArg, -- typename ErrorHandler> --FMT_CONSTEXPR int get_dynamic_spec(FormatArg arg, ErrorHandler eh) { -- unsigned long long value = visit_format_arg(Handler<ErrorHandler>(eh), arg); -- if (value > to_unsigned(max_value<int>())) eh.on_error("number is too big"); -- return static_cast<int>(value); --} -- --struct auto_id {}; -- --template <typename Context, typename ID> --FMT_CONSTEXPR typename Context::format_arg get_arg(Context& ctx, ID id) { -- auto arg = ctx.arg(id); -- if (!arg) ctx.on_error("argument not found"); -- return arg; --} -- --// The standard format specifier handler with checking. --template <typename ParseContext, typename Context> --class specs_handler : public specs_setter<typename Context::char_type> { - public: -- using char_type = typename Context::char_type; -- -- FMT_CONSTEXPR specs_handler(basic_format_specs<char_type>& specs, -- ParseContext& parse_ctx, Context& ctx) -- : specs_setter<char_type>(specs), -- parse_context_(parse_ctx), -- context_(ctx) {} -+ FMT_CONSTEXPR specs_handler(basic_format_specs<Char>& specs, -+ basic_format_parse_context<Char>& parse_ctx, -+ buffer_context<Char>& ctx) -+ : specs_setter<Char>(specs), parse_context_(parse_ctx), context_(ctx) {} - - template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { - this->specs_.width = get_dynamic_spec<width_checker>( -@@ -2585,750 +2105,166 @@ class specs_handler : public specs_setter<typename Context::char_type> { - } - - void on_error(const char* message) { context_.on_error(message); } -- -- private: -- // This is only needed for compatibility with gcc 4.4. -- using format_arg = typename Context::format_arg; -- -- FMT_CONSTEXPR format_arg get_arg(auto_id) { -- return detail::get_arg(context_, parse_context_.next_arg_id()); -- } -- -- FMT_CONSTEXPR format_arg get_arg(int arg_id) { -- parse_context_.check_arg_id(arg_id); -- return detail::get_arg(context_, arg_id); -- } -- -- FMT_CONSTEXPR format_arg get_arg(basic_string_view<char_type> arg_id) { -- parse_context_.check_arg_id(arg_id); -- return detail::get_arg(context_, arg_id); -- } -- -- ParseContext& parse_context_; -- Context& context_; --}; -- --enum class arg_id_kind { none, index, name }; -- --// An argument reference. --template <typename Char> struct arg_ref { -- FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {} -- -- FMT_CONSTEXPR explicit arg_ref(int index) -- : kind(arg_id_kind::index), val(index) {} -- FMT_CONSTEXPR explicit arg_ref(basic_string_view<Char> name) -- : kind(arg_id_kind::name), val(name) {} -- -- FMT_CONSTEXPR arg_ref& operator=(int idx) { -- kind = arg_id_kind::index; -- val.index = idx; -- return *this; -- } -- -- arg_id_kind kind; -- union value { -- FMT_CONSTEXPR value(int id = 0) : index{id} {} -- FMT_CONSTEXPR value(basic_string_view<Char> n) : name(n) {} -- -- int index; -- basic_string_view<Char> name; -- } val; --}; -- --// Format specifiers with width and precision resolved at formatting rather --// than parsing time to allow re-using the same parsed specifiers with --// different sets of arguments (precompilation of format strings). --template <typename Char> --struct dynamic_format_specs : basic_format_specs<Char> { -- arg_ref<Char> width_ref; -- arg_ref<Char> precision_ref; - }; - --// Format spec handler that saves references to arguments representing dynamic --// width and precision to be resolved at formatting time. --template <typename ParseContext> --class dynamic_specs_handler -- : public specs_setter<typename ParseContext::char_type> { -- public: -- using char_type = typename ParseContext::char_type; -- -- FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs<char_type>& specs, -- ParseContext& ctx) -- : specs_setter<char_type>(specs), specs_(specs), context_(ctx) {} -- -- FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler& other) -- : specs_setter<char_type>(other), -- specs_(other.specs_), -- context_(other.context_) {} -- -- template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { -- specs_.width_ref = make_arg_ref(arg_id); -- } -- -- template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { -- specs_.precision_ref = make_arg_ref(arg_id); -- } -- -- FMT_CONSTEXPR void on_error(const char* message) { -- context_.on_error(message); -- } -- -- private: -- using arg_ref_type = arg_ref<char_type>; -- -- FMT_CONSTEXPR arg_ref_type make_arg_ref(int arg_id) { -- context_.check_arg_id(arg_id); -- return arg_ref_type(arg_id); -- } -- -- FMT_CONSTEXPR arg_ref_type make_arg_ref(auto_id) { -- return arg_ref_type(context_.next_arg_id()); -- } -- -- FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view<char_type> arg_id) { -- context_.check_arg_id(arg_id); -- basic_string_view<char_type> format_str( -- context_.begin(), to_unsigned(context_.end() - context_.begin())); -- return arg_ref_type(arg_id); -- } -- -- dynamic_format_specs<char_type>& specs_; -- ParseContext& context_; --}; -- --template <typename Char, typename IDHandler> --FMT_CONSTEXPR const Char* parse_arg_id(const Char* begin, const Char* end, -- IDHandler&& handler) { -- FMT_ASSERT(begin != end, ""); -- Char c = *begin; -- if (c == '}' || c == ':') { -- handler(); -- return begin; -- } -- if (c >= '0' && c <= '9') { -- int index = 0; -- if (c != '0') -- index = parse_nonnegative_int(begin, end, handler); -- else -- ++begin; -- if (begin == end || (*begin != '}' && *begin != ':')) -- handler.on_error("invalid format string"); -- else -- handler(index); -- return begin; -- } -- if (!is_name_start(c)) { -- handler.on_error("invalid format string"); -- return begin; -- } -- auto it = begin; -- do { -- ++it; -- } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9'))); -- handler(basic_string_view<Char>(begin, to_unsigned(it - begin))); -- return it; --} -- --// Adapts SpecHandler to IDHandler API for dynamic width. --template <typename SpecHandler, typename Char> struct width_adapter { -- explicit FMT_CONSTEXPR width_adapter(SpecHandler& h) : handler(h) {} -- -- FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); } -- FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); } -- FMT_CONSTEXPR void operator()(basic_string_view<Char> id) { -- handler.on_dynamic_width(id); -- } -- -- FMT_CONSTEXPR void on_error(const char* message) { -- handler.on_error(message); -- } -- -- SpecHandler& handler; --}; -- --// Adapts SpecHandler to IDHandler API for dynamic precision. --template <typename SpecHandler, typename Char> struct precision_adapter { -- explicit FMT_CONSTEXPR precision_adapter(SpecHandler& h) : handler(h) {} -- -- FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); } -- FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); } -- FMT_CONSTEXPR void operator()(basic_string_view<Char> id) { -- handler.on_dynamic_precision(id); -- } -- -- FMT_CONSTEXPR void on_error(const char* message) { -- handler.on_error(message); -- } -- -- SpecHandler& handler; --}; -- --template <typename Char> --FMT_CONSTEXPR int code_point_length(const Char* begin) { -- if (const_check(sizeof(Char) != 1)) return 1; -- constexpr char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -- 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0}; -- int len = lengths[static_cast<unsigned char>(*begin) >> 3]; -- -- // Compute the pointer to the next character early so that the next -- // iteration can start working on the next character. Neither Clang -- // nor GCC figure out this reordering on their own. -- return len + !len; --} -- --template <typename Char> constexpr bool is_ascii_letter(Char c) { -- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); --} -- --// Converts a character to ASCII. Returns a number > 127 on conversion failure. --template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)> --constexpr Char to_ascii(Char value) { -- return value; --} --template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)> --constexpr typename std::underlying_type<Char>::type to_ascii(Char value) { -- return value; --} -- --// Parses fill and alignment. --template <typename Char, typename Handler> --FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end, -- Handler&& handler) { -- FMT_ASSERT(begin != end, ""); -- auto align = align::none; -- auto p = begin + code_point_length(begin); -- if (p >= end) p = begin; -- for (;;) { -- switch (to_ascii(*p)) { -- case '<': -- align = align::left; -- break; -- case '>': -- align = align::right; -- break; --#if FMT_DEPRECATED_NUMERIC_ALIGN -- case '=': -- align = align::numeric; -- break; --#endif -- case '^': -- align = align::center; -- break; -- } -- if (align != align::none) { -- if (p != begin) { -- auto c = *begin; -- if (c == '{') -- return handler.on_error("invalid fill character '{'"), begin; -- handler.on_fill(basic_string_view<Char>(begin, to_unsigned(p - begin))); -- begin = p + 1; -- } else -- ++begin; -- handler.on_align(align); -- break; -- } else if (p == begin) { -- break; -- } -- p = begin; -- } -- return begin; --} -- --template <typename Char, typename Handler> --FMT_CONSTEXPR const Char* parse_width(const Char* begin, const Char* end, -- Handler&& handler) { -- FMT_ASSERT(begin != end, ""); -- if ('0' <= *begin && *begin <= '9') { -- handler.on_width(parse_nonnegative_int(begin, end, handler)); -- } else if (*begin == '{') { -- ++begin; -- if (begin != end) -- begin = parse_arg_id(begin, end, width_adapter<Handler, Char>(handler)); -- if (begin == end || *begin != '}') -- return handler.on_error("invalid format string"), begin; -- ++begin; -- } -- return begin; --} -- --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 : Char(); -- if ('0' <= c && c <= '9') { -- handler.on_precision(parse_nonnegative_int(begin, end, handler)); -- } else if (c == '{') { -- ++begin; -- if (begin != end) { -- begin = -- parse_arg_id(begin, end, precision_adapter<Handler, Char>(handler)); -- } -- if (begin == end || *begin++ != '}') -- return handler.on_error("invalid format string"), begin; -- } else { -- return handler.on_error("missing precision specifier"), begin; -- } -- handler.end_precision(); -- return begin; --} -- --// Parses standard format specifiers and sends notifications about parsed --// components to handler. --template <typename Char, typename SpecHandler> --FMT_CONSTEXPR const Char* parse_format_specs(const Char* begin, const Char* end, -- SpecHandler&& handler) { -- if (begin == end) return begin; -- -- begin = parse_align(begin, end, handler); -- if (begin == end) return begin; -- -- // Parse sign. -- switch (to_ascii(*begin)) { -- case '+': -- handler.on_plus(); -- ++begin; -+template <template <typename> class Handler, typename Context> -+FMT_CONSTEXPR void handle_dynamic_spec(int& value, -+ arg_ref<typename Context::char_type> ref, -+ Context& ctx) { -+ switch (ref.kind) { -+ case arg_id_kind::none: - break; -- case '-': -- handler.on_minus(); -- ++begin; -+ case arg_id_kind::index: -+ value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.index), -+ ctx.error_handler()); - break; -- case ' ': -- handler.on_space(); -- ++begin; -+ case arg_id_kind::name: -+ value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.name), -+ ctx.error_handler()); - break; - } -- if (begin == end) return begin; -- -- if (*begin == '#') { -- handler.on_hash(); -- if (++begin == end) return begin; -- } -- -- // Parse zero flag. -- if (*begin == '0') { -- handler.on_zero(); -- if (++begin == end) return begin; -- } -- -- begin = parse_width(begin, end, handler); -- if (begin == end) return begin; -- -- // Parse precision. -- if (*begin == '.') { -- begin = parse_precision(begin, end, handler); -- } -- -- // Parse type. -- if (begin != end && *begin != '}') handler.on_type(*begin++); -- return begin; - } - --// Return the result via the out param to workaround gcc bug 77539. --template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*> --FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr& out) { -- for (out = first; out != last; ++out) { -- if (*out == value) return true; -- } -- return false; --} -- --template <> --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, detail::to_unsigned(last - first))); -- return out != nullptr; --} -- --template <typename Handler, typename Char> struct id_adapter { -- Handler& handler; -- int arg_id; -- -- FMT_CONSTEXPR void operator()() { arg_id = handler.on_arg_id(); } -- FMT_CONSTEXPR void operator()(int id) { arg_id = handler.on_arg_id(id); } -- FMT_CONSTEXPR void operator()(basic_string_view<Char> id) { -- arg_id = handler.on_arg_id(id); -- } -- FMT_CONSTEXPR void on_error(const char* message) { -- handler.on_error(message); -- } --}; -+#define FMT_STRING_IMPL(s, base, explicit) \ -+ [] { \ -+ /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ -+ /* Use a macro-like name to avoid shadowing warnings. */ \ -+ struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \ -+ using char_type = fmt::remove_cvref_t<decltype(s[0])>; \ -+ FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \ -+ operator fmt::basic_string_view<char_type>() const { \ -+ return fmt::detail_exported::compile_string_to_view<char_type>(s); \ -+ } \ -+ }; \ -+ return FMT_COMPILE_STRING(); \ -+ }() - --template <typename Char, typename Handler> --FMT_CONSTEXPR const Char* parse_replacement_field(const Char* begin, -- const Char* end, -- Handler&& handler) { -- ++begin; -- if (begin == end) return handler.on_error("invalid format string"), end; -- if (*begin == '}') { -- handler.on_replacement_field(handler.on_arg_id(), begin); -- } else if (*begin == '{') { -- handler.on_text(begin, begin + 1); -- } else { -- auto adapter = id_adapter<Handler, Char>{handler, 0}; -- begin = parse_arg_id(begin, end, adapter); -- Char c = begin != end ? *begin : Char(); -- if (c == '}') { -- handler.on_replacement_field(adapter.arg_id, begin); -- } else if (c == ':') { -- begin = handler.on_format_specs(adapter.arg_id, begin + 1, end); -- if (begin == end || *begin != '}') -- return handler.on_error("unknown format specifier"), end; -- } else { -- return handler.on_error("missing '}' in format string"), end; -- } -- } -- return begin + 1; --} -- --template <bool IS_CONSTEXPR, typename Char, typename Handler> --FMT_CONSTEXPR_DECL FMT_INLINE void parse_format_string( -- basic_string_view<Char> format_str, Handler&& handler) { -- auto begin = format_str.data(); -- auto end = begin + format_str.size(); -- if (end - begin < 32) { -- // Use a simple loop instead of memchr for small strings. -- const Char* p = begin; -- while (p != end) { -- auto c = *p++; -- if (c == '{') { -- handler.on_text(begin, p - 1); -- begin = p = parse_replacement_field(p - 1, end, handler); -- } else if (c == '}') { -- if (p == end || *p != '}') -- return handler.on_error("unmatched '}' in format string"); -- handler.on_text(begin, p); -- begin = ++p; -- } -- } -- handler.on_text(begin, end); -- return; -- } -- struct writer { -- FMT_CONSTEXPR void operator()(const Char* pbegin, const Char* pend) { -- if (pbegin == pend) return; -- for (;;) { -- const Char* p = nullptr; -- if (!find<IS_CONSTEXPR>(pbegin, pend, '}', p)) -- return handler_.on_text(pbegin, pend); -- ++p; -- if (p == pend || *p != '}') -- return handler_.on_error("unmatched '}' in format string"); -- handler_.on_text(pbegin, p); -- pbegin = p + 1; -- } -- } -- Handler& handler_; -- } write{handler}; -- while (begin != end) { -- // Doing two passes with memchr (one for '{' and another for '}') is up to -- // 2.5x faster than the naive one-pass implementation on big format strings. -- const Char* p = begin; -- if (*begin != '{' && !find<IS_CONSTEXPR>(begin + 1, end, '{', p)) -- return write(begin, end); -- write(begin, p); -- begin = parse_replacement_field(p, end, handler); -- } --} -- --template <typename T, typename ParseContext> --FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs( -- ParseContext& ctx) { -- using char_type = typename ParseContext::char_type; -- using context = buffer_context<char_type>; -- using mapped_type = -- conditional_t<detail::mapped_type_constant<T, context>::value != -- type::custom_type, -- decltype(arg_mapper<context>().map(std::declval<T>())), T>; -- auto f = conditional_t<has_formatter<mapped_type, context>::value, -- formatter<mapped_type, char_type>, -- detail::fallback_formatter<T, char_type>>(); -- return f.parse(ctx); --} -- --template <typename OutputIt, typename Char, typename Context> --struct format_handler : detail::error_handler { -- basic_format_parse_context<Char> parse_context; -- Context context; -- -- format_handler(OutputIt out, basic_string_view<Char> str, -- basic_format_args<Context> format_args, detail::locale_ref loc) -- : parse_context(str), context(out, format_args, loc) {} -- -- void on_text(const Char* begin, const Char* end) { -- auto size = to_unsigned(end - begin); -- auto out = context.out(); -- auto&& it = reserve(out, size); -- it = std::copy_n(begin, size, it); -- context.advance_to(out); -- } -- -- int on_arg_id() { return parse_context.next_arg_id(); } -- int on_arg_id(int id) { return parse_context.check_arg_id(id), id; } -- int on_arg_id(basic_string_view<Char> id) { -- int arg_id = context.arg_id(id); -- if (arg_id < 0) on_error("argument not found"); -- return arg_id; -- } -- -- FMT_INLINE void on_replacement_field(int id, const Char*) { -- auto arg = get_arg(context, id); -- context.advance_to(visit_format_arg( -- default_arg_formatter<OutputIt, Char>{context.out(), context.args(), -- context.locale()}, -- arg)); -- } -- -- const Char* on_format_specs(int id, const Char* begin, const Char* end) { -- auto arg = get_arg(context, id); -- if (arg.type() == type::custom_type) { -- advance_to(parse_context, begin); -- visit_format_arg(custom_formatter<Context>(parse_context, context), arg); -- return parse_context.begin(); -- } -- auto specs = basic_format_specs<Char>(); -- if (begin + 1 < end && begin[1] == '}' && is_ascii_letter(*begin)) { -- specs.type = static_cast<char>(*begin++); -- } else { -- using parse_context_t = basic_format_parse_context<Char>; -- specs_checker<specs_handler<parse_context_t, Context>> handler( -- specs_handler<parse_context_t, Context>(specs, parse_context, -- context), -- arg.type()); -- begin = parse_format_specs(begin, end, handler); -- if (begin == end || *begin != '}') -- on_error("missing '}' in format string"); -- } -- context.advance_to(visit_format_arg( -- arg_formatter<OutputIt, Char>(context, &parse_context, &specs), arg)); -- return begin; -- } --}; -+/** -+ \rst -+ Constructs a compile-time format string from a string literal *s*. - --// A parse context with extra argument id checks. It is only used at compile --// time because adding checks at runtime would introduce substantial overhead --// and would be redundant since argument ids are checked when arguments are --// retrieved anyway. --template <typename Char, typename ErrorHandler = error_handler> --class compile_parse_context -- : public basic_format_parse_context<Char, ErrorHandler> { -- private: -- int num_args_; -- using base = basic_format_parse_context<Char, ErrorHandler>; -+ **Example**:: - -- public: -- explicit FMT_CONSTEXPR compile_parse_context( -- basic_string_view<Char> format_str, int num_args = max_value<int>(), -- ErrorHandler eh = {}) -- : base(format_str, eh), num_args_(num_args) {} -+ // A compile-time error because 'd' is an invalid specifier for strings. -+ std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); -+ \endrst -+ */ -+#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string, ) - -- FMT_CONSTEXPR int next_arg_id() { -- int id = base::next_arg_id(); -- if (id >= num_args_) this->on_error("argument not found"); -- return id; -- } -+#if FMT_USE_USER_DEFINED_LITERALS -+template <typename Char> struct udl_formatter { -+ basic_string_view<Char> str; - -- FMT_CONSTEXPR void check_arg_id(int id) { -- base::check_arg_id(id); -- if (id >= num_args_) this->on_error("argument not found"); -+ template <typename... T> -+ auto operator()(T&&... args) const -> std::basic_string<Char> { -+ return vformat(str, fmt::make_args_checked<T...>(str, args...)); - } -- using base::check_arg_id; - }; - --template <typename Char, typename ErrorHandler, typename... Args> --class format_string_checker { -- public: -- explicit FMT_CONSTEXPR format_string_checker( -- basic_string_view<Char> format_str, ErrorHandler eh) -- : context_(format_str, num_args, eh), -- parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {} -+# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -+template <typename T, typename Char, size_t N, -+ fmt::detail_exported::fixed_string<Char, N> Str> -+struct statically_named_arg : view { -+ static constexpr auto name = Str.data; - -- FMT_CONSTEXPR void on_text(const Char*, const Char*) {} -+ const T& value; -+ statically_named_arg(const T& v) : value(v) {} -+}; - -- FMT_CONSTEXPR int on_arg_id() { return context_.next_arg_id(); } -- FMT_CONSTEXPR int on_arg_id(int id) { return context_.check_arg_id(id), id; } -- FMT_CONSTEXPR int on_arg_id(basic_string_view<Char>) { -- on_error("compile-time checks don't support named arguments"); -- return 0; -- } -+template <typename T, typename Char, size_t N, -+ fmt::detail_exported::fixed_string<Char, N> Str> -+struct is_named_arg<statically_named_arg<T, Char, N, Str>> : std::true_type {}; - -- FMT_CONSTEXPR void on_replacement_field(int, const Char*) {} -+template <typename T, typename Char, size_t N, -+ fmt::detail_exported::fixed_string<Char, N> Str> -+struct is_statically_named_arg<statically_named_arg<T, Char, N, Str>> -+ : std::true_type {}; - -- FMT_CONSTEXPR const Char* on_format_specs(int id, const Char* begin, -- const Char*) { -- advance_to(context_, begin); -- return id < num_args ? parse_funcs_[id](context_) : begin; -+template <typename Char, size_t N, -+ fmt::detail_exported::fixed_string<Char, N> Str> -+struct udl_arg { -+ template <typename T> auto operator=(T&& value) const { -+ return statically_named_arg<T, Char, N, Str>(std::forward<T>(value)); - } -+}; -+# else -+template <typename Char> struct udl_arg { -+ const Char* str; - -- FMT_CONSTEXPR void on_error(const char* message) { -- context_.on_error(message); -+ template <typename T> auto operator=(T&& value) const -> named_arg<Char, T> { -+ return {str, std::forward<T>(value)}; - } -- -- private: -- using parse_context_type = compile_parse_context<Char, ErrorHandler>; -- enum { num_args = sizeof...(Args) }; -- -- // Format specifier parsing function. -- using parse_func = const Char* (*)(parse_context_type&); -- -- parse_context_type context_; -- parse_func parse_funcs_[num_args > 0 ? num_args : 1]; - }; -+# endif -+#endif // FMT_USE_USER_DEFINED_LITERALS - --// Converts string literals to basic_string_view. --template <typename Char, size_t N> --FMT_CONSTEXPR basic_string_view<Char> compile_string_to_view( -- const Char (&s)[N]) { -- // Remove trailing null character if needed. Won't be present if this is used -- // with raw character array (i.e. not defined as a string). -- return {s, -- N - ((std::char_traits<Char>::to_int_type(s[N - 1]) == 0) ? 1 : 0)}; --} -- --// Converts string_view to basic_string_view. --template <typename Char> --FMT_CONSTEXPR basic_string_view<Char> compile_string_to_view( -- const std_string_view<Char>& s) { -- return {s.data(), s.size()}; --} -- --#define FMT_STRING_IMPL(s, base) \ -- [] { \ -- /* Use a macro-like name to avoid shadowing warnings. */ \ -- struct FMT_COMPILE_STRING : base { \ -- using char_type = fmt::remove_cvref_t<decltype(s[0])>; \ -- FMT_MAYBE_UNUSED FMT_CONSTEXPR \ -- operator fmt::basic_string_view<char_type>() const { \ -- return fmt::detail::compile_string_to_view<char_type>(s); \ -- } \ -- }; \ -- return FMT_COMPILE_STRING(); \ -- }() -- --/** -- \rst -- Constructs a compile-time format string from a string literal *s*. -- -- **Example**:: -- -- // A compile-time error because 'd' is an invalid specifier for strings. -- std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); -- \endrst -- */ --#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string) -- --template <typename... Args, typename S, -- enable_if_t<(is_compile_string<S>::value), int>> --void check_format_string(S format_str) { -- FMT_CONSTEXPR_DECL auto s = to_string_view(format_str); -- using checker = format_string_checker<typename S::char_type, error_handler, -- remove_cvref_t<Args>...>; -- FMT_CONSTEXPR_DECL bool invalid_format = -- (parse_format_string<true>(s, checker(s, {})), true); -- (void)invalid_format; --} -- --template <template <typename> class Handler, typename Context> --void handle_dynamic_spec(int& value, arg_ref<typename Context::char_type> ref, -- Context& ctx) { -- switch (ref.kind) { -- case arg_id_kind::none: -- break; -- case arg_id_kind::index: -- value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.index), -- ctx.error_handler()); -- break; -- case arg_id_kind::name: -- value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.name), -- ctx.error_handler()); -- break; -- } -+template <typename Locale, typename Char> -+auto vformat(const Locale& loc, basic_string_view<Char> format_str, -+ basic_format_args<buffer_context<type_identity_t<Char>>> args) -+ -> std::basic_string<Char> { -+ basic_memory_buffer<Char> buffer; -+ detail::vformat_to(buffer, format_str, args, detail::locale_ref(loc)); -+ return {buffer.data(), buffer.size()}; - } - --using format_func = void (*)(detail::buffer<char>&, int, string_view); -+using format_func = void (*)(detail::buffer<char>&, int, const char*); - - FMT_API void format_error_code(buffer<char>& out, int error_code, - string_view message) FMT_NOEXCEPT; - - FMT_API void report_error(format_func func, int error_code, -- string_view message) FMT_NOEXCEPT; --} // namespace detail -+ const char* message) FMT_NOEXCEPT; -+FMT_END_DETAIL_NAMESPACE - --template <typename OutputIt, typename Char> --using arg_formatter FMT_DEPRECATED_ALIAS = -- detail::arg_formatter<OutputIt, Char>; -+FMT_API auto vsystem_error(int error_code, string_view format_str, -+ format_args args) -> std::system_error; - - /** -- An error returned by an operating system or a language runtime, -- for example a file opening error. --*/ --FMT_CLASS_API --class FMT_API system_error : public std::runtime_error { -- private: -- void init(int err_code, string_view format_str, format_args args); -- -- protected: -- int error_code_; -+ \rst -+ Constructs :class:`std::system_error` with a message formatted with -+ ``fmt::format(fmt, args...)``. -+ *error_code* is a system error code as given by ``errno``. - -- system_error() : std::runtime_error(""), error_code_(0) {} -+ **Example**:: - -- public: -- /** -- \rst -- Constructs a :class:`fmt::system_error` object with a description -- formatted with `fmt::format_system_error`. *message* and additional -- arguments passed into the constructor are formatted similarly to -- `fmt::format`. -- -- **Example**:: -- -- // This throws a system_error with the description -- // cannot open file 'madeup': No such file or directory -- // or similar (system message may vary). -- const char *filename = "madeup"; -- std::FILE *file = std::fopen(filename, "r"); -- if (!file) -- throw fmt::system_error(errno, "cannot open file '{}'", filename); -- \endrst -- */ -- template <typename... Args> -- system_error(int error_code, string_view message, const Args&... args) -- : std::runtime_error("") { -- init(error_code, message, make_format_args(args...)); -- } -- system_error(const system_error&) = default; -- system_error& operator=(const system_error&) = default; -- system_error(system_error&&) = default; -- system_error& operator=(system_error&&) = default; -- ~system_error() FMT_NOEXCEPT FMT_OVERRIDE; -- -- int error_code() const { return error_code_; } --}; -+ // This throws std::system_error with the description -+ // cannot open file 'madeup': No such file or directory -+ // or similar (system message may vary). -+ const char* filename = "madeup"; -+ std::FILE* file = std::fopen(filename, "r"); -+ if (!file) -+ throw fmt::system_error(errno, "cannot open file '{}'", filename); -+ \endrst -+*/ -+template <typename... T> -+auto system_error(int error_code, format_string<T...> fmt, T&&... args) -+ -> std::system_error { -+ return vsystem_error(error_code, fmt, fmt::make_format_args(args...)); -+} - - /** - \rst -- Formats an error returned by an operating system or a language runtime, -- for example a file opening error, and writes it to *out* in the following -- form: -+ Formats an error message for an error returned by an operating system or a -+ language runtime, for example a file opening error, and writes it to *out*. -+ The format is the same as the one used by ``std::system_error(ec, message)`` -+ where ``ec`` is ``std::error_code(error_code, std::generic_category()})``. -+ It is implementation-defined but normally looks like: - - .. parsed-literal:: - *<message>*: *<system-message>* - -- where *<message>* is the passed message and *<system-message>* is -- the system message corresponding to the error code. -+ where *<message>* is the passed message and *<system-message>* is the system -+ message corresponding to the error code. - *error_code* is a system error code as given by ``errno``. -- If *error_code* is not a valid error code such as -1, the system message -- may look like "Unknown error -1" and is platform-dependent. - \endrst - */ - FMT_API void format_system_error(detail::buffer<char>& out, int error_code, -- string_view message) FMT_NOEXCEPT; -+ const char* message) FMT_NOEXCEPT; - - // Reports a system error without throwing an exception. - // Can be used to report errors from destructors. - FMT_API void report_system_error(int error_code, -- string_view message) FMT_NOEXCEPT; -+ const char* message) FMT_NOEXCEPT; - - /** Fast integer formatter. */ - class format_int { -@@ -3339,12 +2275,12 @@ class format_int { - mutable char buffer_[buffer_size]; - char* str_; - -- template <typename UInt> char* format_unsigned(UInt value) { -+ template <typename UInt> auto format_unsigned(UInt value) -> char* { - auto n = static_cast<detail::uint32_or_64_or_128_t<UInt>>(value); - return detail::format_decimal(buffer_, n, buffer_size - 1).begin; - } - -- template <typename Int> char* format_signed(Int value) { -+ template <typename Int> auto format_signed(Int value) -> char* { - auto abs_value = static_cast<detail::uint32_or_64_or_128_t<Int>>(value); - bool negative = value < 0; - if (negative) abs_value = 0 - abs_value; -@@ -3363,7 +2299,7 @@ class format_int { - : str_(format_unsigned(value)) {} - - /** Returns the number of characters written to the output buffer. */ -- size_t size() const { -+ auto size() const -> size_t { - return detail::to_unsigned(buffer_ - str_ + buffer_size - 1); - } - -@@ -3371,13 +2307,13 @@ class format_int { - Returns a pointer to the output buffer content. No terminating null - character is appended. - */ -- const char* data() const { return str_; } -+ auto data() const -> const char* { return str_; } - - /** - Returns a pointer to the output buffer content with terminating null - character appended. - */ -- const char* c_str() const { -+ auto c_str() const -> const char* { - buffer_[buffer_size - 1] = '\0'; - return str_; - } -@@ -3387,104 +2323,37 @@ class format_int { - Returns the content of the output buffer as an ``std::string``. - \endrst - */ -- std::string str() const { return std::string(str_, size()); } -+ auto str() const -> std::string { return std::string(str_, size()); } - }; - --// A formatter specialization for the core types corresponding to detail::type --// constants. - template <typename T, typename Char> --struct formatter<T, Char, -- enable_if_t<detail::type_constant<T, Char>::value != -- detail::type::custom_type>> { -- FMT_CONSTEXPR formatter() = default; -- -- // Parses format specifiers stopping either at the end of the range or at the -- // terminating '}'. -- template <typename ParseContext> -- FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { -- using handler_type = detail::dynamic_specs_handler<ParseContext>; -- auto type = detail::type_constant<T, Char>::value; -- detail::specs_checker<handler_type> handler(handler_type(specs_, ctx), -- type); -- auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); -- auto eh = ctx.error_handler(); -- switch (type) { -- case detail::type::none_type: -- FMT_ASSERT(false, "invalid argument type"); -- break; -- case detail::type::int_type: -- case detail::type::uint_type: -- case detail::type::long_long_type: -- case detail::type::ulong_long_type: -- case detail::type::int128_type: -- case detail::type::uint128_type: -- case detail::type::bool_type: -- handle_int_type_spec(specs_.type, -- detail::int_type_checker<decltype(eh)>(eh)); -- break; -- case detail::type::char_type: -- handle_char_specs( -- &specs_, detail::char_specs_checker<decltype(eh)>(specs_.type, eh)); -- break; -- case detail::type::float_type: -- if (detail::const_check(FMT_USE_FLOAT)) -- detail::parse_float_type_spec(specs_, eh); -- else -- FMT_ASSERT(false, "float support disabled"); -- break; -- case detail::type::double_type: -- if (detail::const_check(FMT_USE_DOUBLE)) -- detail::parse_float_type_spec(specs_, eh); -- else -- FMT_ASSERT(false, "double support disabled"); -- break; -- case detail::type::long_double_type: -- if (detail::const_check(FMT_USE_LONG_DOUBLE)) -- detail::parse_float_type_spec(specs_, eh); -- else -- FMT_ASSERT(false, "long double support disabled"); -- break; -- case detail::type::cstring_type: -- detail::handle_cstring_type_spec( -- specs_.type, detail::cstring_type_checker<decltype(eh)>(eh)); -- break; -- case detail::type::string_type: -- detail::check_string_type_spec(specs_.type, eh); -- break; -- case detail::type::pointer_type: -- detail::check_pointer_type_spec(specs_.type, eh); -- break; -- case detail::type::custom_type: -- // Custom format specifiers should be checked in parse functions of -- // formatter specializations. -- break; -- } -- return it; -- } -- -- template <typename FormatContext> -- auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) { -- detail::handle_dynamic_spec<detail::width_checker>(specs_.width, -- specs_.width_ref, ctx); -+template <typename FormatContext> -+FMT_CONSTEXPR FMT_INLINE auto -+formatter<T, Char, -+ enable_if_t<detail::type_constant<T, Char>::value != -+ detail::type::custom_type>>::format(const T& val, -+ FormatContext& ctx) -+ const -> decltype(ctx.out()) { -+ if (specs_.width_ref.kind != detail::arg_id_kind::none || -+ specs_.precision_ref.kind != detail::arg_id_kind::none) { -+ auto specs = specs_; -+ detail::handle_dynamic_spec<detail::width_checker>(specs.width, -+ specs.width_ref, ctx); - detail::handle_dynamic_spec<detail::precision_checker>( -- specs_.precision, specs_.precision_ref, ctx); -- using af = detail::arg_formatter<typename FormatContext::iterator, -- typename FormatContext::char_type>; -- return visit_format_arg(af(ctx, nullptr, &specs_), -- detail::make_arg<FormatContext>(val)); -+ specs.precision, specs.precision_ref, ctx); -+ return detail::write<Char>(ctx.out(), val, specs, ctx.locale()); - } -+ return detail::write<Char>(ctx.out(), val, specs_, ctx.locale()); -+} - -- private: -- detail::dynamic_format_specs<Char> specs_; --}; -- --#define FMT_FORMAT_AS(Type, Base) \ -- template <typename Char> \ -- struct formatter<Type, Char> : formatter<Base, Char> { \ -- template <typename FormatContext> \ -- auto format(Type const& val, FormatContext& ctx) -> decltype(ctx.out()) { \ -- return formatter<Base, Char>::format(val, ctx); \ -- } \ -+#define FMT_FORMAT_AS(Type, Base) \ -+ template <typename Char> \ -+ struct formatter<Type, Char> : formatter<Base, Char> { \ -+ template <typename FormatContext> \ -+ auto format(Type const& val, FormatContext& ctx) const \ -+ -> decltype(ctx.out()) { \ -+ return formatter<Base, Char>::format(static_cast<Base>(val), ctx); \ -+ } \ - } - - FMT_FORMAT_AS(signed char, int); -@@ -3501,7 +2370,7 @@ FMT_FORMAT_AS(detail::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()) { -+ auto format(void* val, FormatContext& ctx) const -> decltype(ctx.out()) { - return formatter<const void*, Char>::format(val, ctx); - } - }; -@@ -3509,7 +2378,8 @@ struct formatter<void*, Char> : formatter<const void*, Char> { - 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()) { -+ FMT_CONSTEXPR auto format(const Char* val, FormatContext& ctx) const -+ -> decltype(ctx.out()) { - return formatter<basic_string_view<Char>, Char>::format(val, ctx); - } - }; -@@ -3528,21 +2398,29 @@ struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> { - // }; - template <typename Char = char> class dynamic_formatter { - private: -+ detail::dynamic_format_specs<Char> specs_; -+ const Char* format_str_; -+ - struct null_handler : detail::error_handler { - void on_align(align_t) {} -- void on_plus() {} -- void on_minus() {} -- void on_space() {} -+ void on_sign(sign_t) {} - void on_hash() {} - }; - -+ template <typename Context> void handle_specs(Context& ctx) { -+ detail::handle_dynamic_spec<detail::width_checker>(specs_.width, -+ specs_.width_ref, ctx); -+ detail::handle_dynamic_spec<detail::precision_checker>( -+ specs_.precision, specs_.precision_ref, ctx); -+ } -+ - public: - template <typename ParseContext> -- auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { -+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - format_str_ = ctx.begin(); - // Checks are deferred to formatting time when the argument type is known. - detail::dynamic_specs_handler<ParseContext> handler(specs_, ctx); -- return parse_format_specs(ctx.begin(), ctx.end(), handler); -+ return detail::parse_format_specs(ctx.begin(), ctx.end(), handler); - } - - template <typename T, typename FormatContext> -@@ -3551,46 +2429,13 @@ template <typename Char = char> class dynamic_formatter { - detail::specs_checker<null_handler> checker( - null_handler(), detail::mapped_type_constant<T, FormatContext>::value); - checker.on_align(specs_.align); -- switch (specs_.sign) { -- case sign::none: -- break; -- case sign::plus: -- checker.on_plus(); -- break; -- case sign::minus: -- checker.on_minus(); -- break; -- case sign::space: -- checker.on_space(); -- break; -- } -+ if (specs_.sign != sign::none) checker.on_sign(specs_.sign); - if (specs_.alt) checker.on_hash(); - if (specs_.precision >= 0) checker.end_precision(); -- using af = detail::arg_formatter<typename FormatContext::iterator, -- typename FormatContext::char_type>; -- visit_format_arg(af(ctx, nullptr, &specs_), -- detail::make_arg<FormatContext>(val)); -- return ctx.out(); -+ return detail::write<Char>(ctx.out(), val, specs_, ctx.locale()); - } -- -- private: -- template <typename Context> void handle_specs(Context& ctx) { -- detail::handle_dynamic_spec<detail::width_checker>(specs_.width, -- specs_.width_ref, ctx); -- detail::handle_dynamic_spec<detail::precision_checker>( -- specs_.precision, specs_.precision_ref, ctx); -- } -- -- detail::dynamic_format_specs<Char> specs_; -- const Char* format_str_; - }; - --template <typename Char, typename ErrorHandler> --FMT_CONSTEXPR void advance_to( -- basic_format_parse_context<Char, ErrorHandler>& ctx, const Char* p) { -- ctx.advance_to(ctx.begin() + (p - &*ctx.begin())); --} -- - /** - \rst - Converts ``p`` to ``const void*`` for pointer formatting. -@@ -3600,11 +2445,14 @@ FMT_CONSTEXPR void advance_to( - auto s = fmt::format("{}", fmt::ptr(p)); - \endrst - */ --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) { -+template <typename T> auto ptr(T p) -> const void* { -+ static_assert(std::is_pointer<T>::value, ""); -+ return detail::bit_cast<const void*>(p); -+} -+template <typename T> auto ptr(const std::unique_ptr<T>& p) -> const void* { - return p.get(); - } --template <typename T> inline const void* ptr(const std::shared_ptr<T>& p) { -+template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* { - return p.get(); - } - -@@ -3642,31 +2490,61 @@ template <> struct formatter<bytes> { - } - }; - --template <typename It, typename Sentinel, typename Char> --struct arg_join : detail::view { -+template <typename It, typename Sentinel, typename Char = char> -+struct join_view : detail::view { - It begin; - Sentinel end; - basic_string_view<Char> sep; - -- arg_join(It b, Sentinel e, basic_string_view<Char> s) -+ join_view(It b, Sentinel e, basic_string_view<Char> s) - : begin(b), end(e), sep(s) {} - }; - - template <typename It, typename Sentinel, typename Char> --struct formatter<arg_join<It, Sentinel, Char>, Char> -- : formatter<typename std::iterator_traits<It>::value_type, Char> { -+using arg_join FMT_DEPRECATED_ALIAS = join_view<It, Sentinel, Char>; -+ -+template <typename It, typename Sentinel, typename Char> -+struct formatter<join_view<It, Sentinel, Char>, Char> { -+ private: -+ using value_type = typename std::iterator_traits<It>::value_type; -+ using context = buffer_context<Char>; -+ using mapper = detail::arg_mapper<context>; -+ -+ template <typename T, FMT_ENABLE_IF(has_formatter<T, context>::value)> -+ static auto map(const T& value) -> const T& { -+ return value; -+ } -+ template <typename T, FMT_ENABLE_IF(!has_formatter<T, context>::value)> -+ static auto map(const T& value) -> decltype(mapper().map(value)) { -+ return mapper().map(value); -+ } -+ -+ using formatter_type = -+ conditional_t<is_formattable<value_type, Char>::value, -+ formatter<remove_cvref_t<decltype(map( -+ std::declval<const value_type&>()))>, -+ Char>, -+ detail::fallback_formatter<value_type, Char>>; -+ -+ formatter_type value_formatter_; -+ -+ public: -+ template <typename ParseContext> -+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { -+ return value_formatter_.parse(ctx); -+ } -+ - template <typename FormatContext> -- auto format(const arg_join<It, Sentinel, Char>& value, FormatContext& ctx) -+ auto format(const join_view<It, Sentinel, Char>& value, FormatContext& ctx) - -> decltype(ctx.out()) { -- using base = formatter<typename std::iterator_traits<It>::value_type, Char>; - auto it = value.begin; - auto out = ctx.out(); - if (it != value.end) { -- out = base::format(*it++, ctx); -+ out = value_formatter_.format(map(*it++), ctx); - while (it != value.end) { -- out = std::copy(value.sep.begin(), value.sep.end(), out); -+ out = detail::copy_str<Char>(value.sep.begin(), value.sep.end(), out); - ctx.advance_to(out); -- out = base::format(*it++, ctx); -+ out = value_formatter_.format(map(*it++), ctx); - } - } - return out; -@@ -3674,16 +2552,11 @@ struct formatter<arg_join<It, Sentinel, Char>, Char> - }; - - /** -- Returns an object that formats the iterator range `[begin, end)` with elements -- separated by `sep`. -+ Returns an object that formats the iterator range `[begin, end)` with -+ elements separated by `sep`. - */ - template <typename It, typename Sentinel> --arg_join<It, Sentinel, char> join(It begin, Sentinel end, string_view sep) { -- return {begin, end, sep}; --} -- --template <typename It, typename Sentinel> --arg_join<It, Sentinel, wchar_t> join(It begin, Sentinel end, wstring_view sep) { -+auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> { - return {begin, end, sep}; - } - -@@ -3704,14 +2577,8 @@ arg_join<It, Sentinel, wchar_t> join(It begin, Sentinel end, wstring_view sep) { - \endrst - */ - template <typename Range> --arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>, char> join( -- Range&& range, string_view sep) { -- return join(std::begin(range), std::end(range), sep); --} -- --template <typename Range> --arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>, wchar_t> join( -- Range&& range, wstring_view sep) { -+auto join(Range&& range, string_view sep) -+ -> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>> { - return join(std::begin(range), std::end(range), sep); - } - -@@ -3727,229 +2594,229 @@ arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>, wchar_t> join( - \endrst - */ - template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> --inline std::string to_string(const T& value) { -- std::string result; -+inline auto to_string(const T& value) -> std::string { -+ auto result = std::string(); - detail::write<char>(std::back_inserter(result), value); - return result; - } - - template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> --inline std::string to_string(T value) { -- // The buffer should be large enough to store the number including the sign or -- // "false" for bool. -+inline auto to_string(T value) -> std::string { -+ // The buffer should be large enough to store the number including the sign -+ // or "false" for bool. - constexpr int max_size = detail::digits10<T>() + 2; - char buffer[max_size > 5 ? static_cast<unsigned>(max_size) : 5]; - char* begin = buffer; - return std::string(begin, detail::write<char>(begin, value)); - } - --/** -- Converts *value* to ``std::wstring`` using the default format for type *T*. -- */ --template <typename T> inline std::wstring to_wstring(const T& value) { -- return format(L"{}", value); --} -- - template <typename Char, size_t SIZE> --std::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE>& buf) { -+auto to_string(const basic_memory_buffer<Char, SIZE>& buf) -+ -> std::basic_string<Char> { - auto size = buf.size(); - detail::assume(size < std::basic_string<Char>().max_size()); - return std::basic_string<Char>(buf.data(), size); - } - -+FMT_BEGIN_DETAIL_NAMESPACE -+ - template <typename Char> --void detail::vformat_to( -- detail::buffer<Char>& buf, basic_string_view<Char> format_str, -- basic_format_args<buffer_context<type_identity_t<Char>>> args, -- detail::locale_ref loc) { -- using iterator = typename buffer_context<Char>::iterator; -+void vformat_to(buffer<Char>& buf, basic_string_view<Char> fmt, -+ basic_format_args<buffer_context<type_identity_t<Char>>> args, -+ locale_ref loc) { -+ // workaround for msvc bug regarding name-lookup in module -+ // link names into function scope -+ using detail::arg_formatter; -+ using detail::buffer_appender; -+ using detail::custom_formatter; -+ using detail::default_arg_formatter; -+ using detail::get_arg; -+ using detail::locale_ref; -+ using detail::parse_format_specs; -+ using detail::specs_checker; -+ using detail::specs_handler; -+ using detail::to_unsigned; -+ using detail::type; -+ using detail::write; - auto out = buffer_appender<Char>(buf); -- if (format_str.size() == 2 && equal2(format_str.data(), "{}")) { -+ if (fmt.size() == 2 && equal2(fmt.data(), "{}")) { - auto arg = args.get(0); - if (!arg) error_handler().on_error("argument not found"); -- visit_format_arg(default_arg_formatter<iterator, Char>{out, args, loc}, -- arg); -+ visit_format_arg(default_arg_formatter<Char>{out, args, loc}, arg); - return; - } -- format_handler<iterator, Char, buffer_context<Char>> h(out, format_str, args, -- loc); -- parse_format_string<false>(format_str, h); --} - --#ifndef FMT_HEADER_ONLY --extern template void detail::vformat_to(detail::buffer<char>&, string_view, -- basic_format_args<format_context>, -- detail::locale_ref); --namespace detail { -+ struct format_handler : error_handler { -+ basic_format_parse_context<Char> parse_context; -+ buffer_context<Char> context; - --extern template FMT_API std::string grouping_impl<char>(locale_ref loc); --extern template FMT_API std::string grouping_impl<wchar_t>(locale_ref loc); --extern template FMT_API char thousands_sep_impl<char>(locale_ref loc); --extern template FMT_API wchar_t thousands_sep_impl<wchar_t>(locale_ref loc); --extern template FMT_API char decimal_point_impl(locale_ref loc); --extern template FMT_API wchar_t decimal_point_impl(locale_ref loc); --extern template int format_float<double>(double value, int precision, -- float_specs specs, buffer<char>& buf); --extern template int format_float<long double>(long double value, int precision, -- float_specs specs, -- buffer<char>& buf); --int snprintf_float(float value, int precision, float_specs specs, -- buffer<char>& buf) = delete; --extern template int snprintf_float<double>(double value, int precision, -- float_specs specs, -- buffer<char>& buf); --extern template int snprintf_float<long double>(long double value, -- int precision, -- float_specs specs, -- buffer<char>& buf); --} // namespace detail --#endif -+ format_handler(buffer_appender<Char> out, basic_string_view<Char> str, -+ basic_format_args<buffer_context<Char>> args, locale_ref loc) -+ : parse_context(str), context(out, args, loc) {} - --template <typename S, typename Char = char_t<S>, -- FMT_ENABLE_IF(detail::is_string<S>::value)> --inline void vformat_to( -- detail::buffer<Char>& buf, const S& format_str, -- basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args) { -- return detail::vformat_to(buf, to_string_view(format_str), args); --} -- --template <typename S, typename... Args, size_t SIZE = inline_buffer_size, -- typename Char = enable_if_t<detail::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, Args&&... args) { -- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); -- detail::vformat_to(buf, to_string_view(format_str), vargs); -- return detail::buffer_appender<Char>(buf); --} -- --template <typename OutputIt, typename Char = char> --using format_context_t = basic_format_context<OutputIt, Char>; -- --template <typename OutputIt, typename Char = char> --using format_args_t = basic_format_args<format_context_t<OutputIt, Char>>; -- --template <typename OutputIt, typename Char = typename OutputIt::value_type> --using format_to_n_context FMT_DEPRECATED_ALIAS = buffer_context<Char>; -- --template <typename OutputIt, typename Char = typename OutputIt::value_type> --using format_to_n_args FMT_DEPRECATED_ALIAS = -- basic_format_args<buffer_context<Char>>; -- --template <typename OutputIt, typename Char, typename... Args> --FMT_DEPRECATED format_arg_store<buffer_context<Char>, Args...> --make_format_to_n_args(const Args&... args) { -- return format_arg_store<buffer_context<Char>, Args...>(args...); --} -+ void on_text(const Char* begin, const Char* end) { -+ auto text = basic_string_view<Char>(begin, to_unsigned(end - begin)); -+ context.advance_to(write<Char>(context.out(), text)); -+ } - --template <typename Char, enable_if_t<(!std::is_same<Char, char>::value), int>> --std::basic_string<Char> detail::vformat( -- basic_string_view<Char> format_str, -- basic_format_args<buffer_context<type_identity_t<Char>>> args) { -- basic_memory_buffer<Char> buffer; -- detail::vformat_to(buffer, format_str, args); -- return to_string(buffer); --} -+ FMT_CONSTEXPR auto on_arg_id() -> int { -+ return parse_context.next_arg_id(); -+ } -+ FMT_CONSTEXPR auto on_arg_id(int id) -> int { -+ return parse_context.check_arg_id(id), id; -+ } -+ FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int { -+ int arg_id = context.arg_id(id); -+ if (arg_id < 0) on_error("argument not found"); -+ return arg_id; -+ } - --template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)> --void vprint(std::FILE* f, basic_string_view<Char> format_str, -- wformat_args args) { -- wmemory_buffer buffer; -- detail::vformat_to(buffer, format_str, args); -- buffer.push_back(L'\0'); -- if (std::fputws(buffer.data(), f) == -1) -- FMT_THROW(system_error(errno, "cannot write to file")); --} -+ FMT_INLINE void on_replacement_field(int id, const Char*) { -+ auto arg = get_arg(context, id); -+ context.advance_to(visit_format_arg( -+ default_arg_formatter<Char>{context.out(), context.args(), -+ context.locale()}, -+ arg)); -+ } - --template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)> --void vprint(basic_string_view<Char> format_str, wformat_args args) { -- vprint(stdout, format_str, args); -+ auto on_format_specs(int id, const Char* begin, const Char* end) -+ -> const Char* { -+ auto arg = get_arg(context, id); -+ if (arg.type() == type::custom_type) { -+ parse_context.advance_to(parse_context.begin() + -+ (begin - &*parse_context.begin())); -+ visit_format_arg(custom_formatter<Char>{parse_context, context}, arg); -+ return parse_context.begin(); -+ } -+ auto specs = basic_format_specs<Char>(); -+ specs_checker<specs_handler<Char>> handler( -+ specs_handler<Char>(specs, parse_context, context), arg.type()); -+ begin = parse_format_specs(begin, end, handler); -+ if (begin == end || *begin != '}') -+ on_error("missing '}' in format string"); -+ auto f = arg_formatter<Char>{context.out(), specs, context.locale()}; -+ context.advance_to(visit_format_arg(f, arg)); -+ return begin; -+ } -+ }; -+ detail::parse_format_string<false>(fmt, format_handler(out, fmt, args, loc)); - } - --#if FMT_USE_USER_DEFINED_LITERALS --namespace detail { -- --# if FMT_USE_UDL_TEMPLATE --template <typename Char, Char... CHARS> class udl_formatter { -- public: -- template <typename... Args> -- std::basic_string<Char> operator()(Args&&... args) const { -- static FMT_CONSTEXPR_DECL Char s[] = {CHARS..., '\0'}; -- return format(FMT_STRING(s), std::forward<Args>(args)...); -- } --}; --# else --template <typename Char> struct udl_formatter { -- basic_string_view<Char> str; -- -- template <typename... Args> -- std::basic_string<Char> operator()(Args&&... args) const { -- return format(str, std::forward<Args>(args)...); -- } --}; --# endif // FMT_USE_UDL_TEMPLATE -- --template <typename Char> struct udl_arg { -- const Char* str; -- -- template <typename T> named_arg<Char, T> operator=(T&& value) const { -- return {str, std::forward<T>(value)}; -- } --}; --} // namespace detail -- -+#ifndef FMT_HEADER_ONLY -+extern template void vformat_to(detail::buffer<char>&, string_view, -+ basic_format_args<format_context>, -+ detail::locale_ref); -+ -+extern template FMT_API auto thousands_sep_impl<char>(locale_ref) -+ -> thousands_sep_result<char>; -+extern template FMT_API auto thousands_sep_impl<wchar_t>(locale_ref) -+ -> thousands_sep_result<wchar_t>; -+extern template FMT_API auto decimal_point_impl(locale_ref) -> char; -+extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; -+extern template auto format_float<double>(double value, int precision, -+ float_specs specs, buffer<char>& buf) -+ -> int; -+extern template auto format_float<long double>(long double value, int precision, -+ float_specs specs, -+ buffer<char>& buf) -> int; -+void snprintf_float(float, int, float_specs, buffer<char>&) = delete; -+extern template auto snprintf_float<double>(double value, int precision, -+ float_specs specs, -+ buffer<char>& buf) -> int; -+extern template auto snprintf_float<long double>(long double value, -+ int precision, -+ float_specs specs, -+ buffer<char>& buf) -> int; -+#endif // FMT_HEADER_ONLY -+ -+FMT_END_DETAIL_NAMESPACE - inline namespace literals { --# if FMT_USE_UDL_TEMPLATE --# pragma GCC diagnostic push --# pragma GCC diagnostic ignored "-Wpedantic" --# if FMT_CLANG_VERSION --# pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template" --# endif --template <typename Char, Char... CHARS> --FMT_CONSTEXPR detail::udl_formatter<Char, CHARS...> operator""_format() { -- return {}; --} --# pragma GCC diagnostic pop --# else - /** - \rst -- User-defined literal equivalent of :func:`fmt::format`. -+ User-defined literal equivalent of :func:`fmt::arg`. - - **Example**:: - - using namespace fmt::literals; -- std::string message = "The answer is {}"_format(42); -+ fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); - \endrst - */ --FMT_CONSTEXPR detail::udl_formatter<char> operator"" _format(const char* s, -- size_t n) { -- return {{s, n}}; -+#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -+template <detail_exported::fixed_string Str> -+constexpr auto operator""_a() -+ -> detail::udl_arg<remove_cvref_t<decltype(Str.data[0])>, -+ sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str> { -+ return {}; - } --FMT_CONSTEXPR detail::udl_formatter<wchar_t> operator"" _format( -- const wchar_t* s, size_t n) { -- return {{s, n}}; -+#else -+constexpr auto operator"" _a(const char* s, size_t) -> detail::udl_arg<char> { -+ return {s}; - } --# endif // FMT_USE_UDL_TEMPLATE -+#endif - - /** - \rst -- User-defined literal equivalent of :func:`fmt::arg`. -+ User-defined literal equivalent of :func:`fmt::format`. - - **Example**:: - - using namespace fmt::literals; -- fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); -+ std::string message = "The answer is {}"_format(42); - \endrst - */ --FMT_CONSTEXPR detail::udl_arg<char> operator"" _a(const char* s, size_t) { -- return {s}; --} --FMT_CONSTEXPR detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) { -- return {s}; -+constexpr auto operator"" _format(const char* s, size_t n) -+ -> detail::udl_formatter<char> { -+ return {{s, n}}; - } - } // namespace literals --#endif // FMT_USE_USER_DEFINED_LITERALS -+ -+template <typename Locale, FMT_ENABLE_IF(detail::is_locale<Locale>::value)> -+inline auto vformat(const Locale& loc, string_view fmt, format_args args) -+ -> std::string { -+ return detail::vformat(loc, fmt, args); -+} -+ -+template <typename Locale, typename... T, -+ FMT_ENABLE_IF(detail::is_locale<Locale>::value)> -+inline auto format(const Locale& loc, format_string<T...> fmt, T&&... args) -+ -> std::string { -+ return vformat(loc, string_view(fmt), fmt::make_format_args(args...)); -+} -+ -+template <typename... T, size_t SIZE, typename Allocator> -+FMT_DEPRECATED auto format_to(basic_memory_buffer<char, SIZE, Allocator>& buf, -+ format_string<T...> fmt, T&&... args) -+ -> appender { -+ detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...)); -+ return appender(buf); -+} -+ -+template <typename OutputIt, typename Locale, -+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value&& -+ detail::is_locale<Locale>::value)> -+auto vformat_to(OutputIt out, const Locale& loc, string_view fmt, -+ format_args args) -> OutputIt { -+ using detail::get_buffer; -+ auto&& buf = get_buffer<char>(out); -+ detail::vformat_to(buf, fmt, args, detail::locale_ref(loc)); -+ return detail::get_iterator(buf); -+} -+ -+template <typename OutputIt, typename Locale, typename... T, -+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value&& -+ detail::is_locale<Locale>::value)> -+FMT_INLINE auto format_to(OutputIt out, const Locale& loc, -+ format_string<T...> fmt, T&&... args) -> OutputIt { -+ return vformat_to(out, loc, fmt, fmt::make_format_args(args...)); -+} -+ -+FMT_MODULE_EXPORT_END - FMT_END_NAMESPACE - -+#ifdef FMT_DEPRECATED_INCLUDE_XCHAR -+# include "xchar.h" -+#endif -+ - #ifdef FMT_HEADER_ONLY - # define FMT_FUNC inline - # include "format-inl.h" -diff --git a/include/spdlog/fmt/bundled/locale.h b/include/spdlog/fmt/bundled/locale.h -index 7301bf92..7571b526 100644 ---- a/include/spdlog/fmt/bundled/locale.h -+++ b/include/spdlog/fmt/bundled/locale.h -@@ -1,64 +1,2 @@ --// Formatting library for C++ - std::locale support --// --// Copyright (c) 2012 - present, Victor Zverovich --// All rights reserved. --// --// For the license information refer to format.h. -- --#ifndef FMT_LOCALE_H_ --#define FMT_LOCALE_H_ -- --#include <locale> -- --#include "format.h" -- --FMT_BEGIN_NAMESPACE -- --namespace detail { --template <typename Char> --std::basic_string<Char> vformat( -- const std::locale& loc, basic_string_view<Char> format_str, -- basic_format_args<buffer_context<type_identity_t<Char>>> args) { -- basic_memory_buffer<Char> buffer; -- detail::vformat_to(buffer, format_str, args, detail::locale_ref(loc)); -- return fmt::to_string(buffer); --} --} // namespace detail -- --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<buffer_context<type_identity_t<Char>>> args) { -- return detail::vformat(loc, to_string_view(format_str), 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, Args&&... args) { -- return detail::vformat(loc, to_string_view(format_str), -- fmt::make_args_checked<Args...>(format_str, args...)); --} -- --template <typename S, typename OutputIt, typename... Args, -- typename Char = char_t<S>, -- FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)> --inline OutputIt vformat_to( -- OutputIt out, const std::locale& loc, const S& format_str, -- basic_format_args<buffer_context<type_identity_t<Char>>> args) { -- decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out)); -- vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc)); -- return detail::get_iterator(buf); --} -- --template <typename OutputIt, typename S, typename... Args, -- bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value> --inline auto format_to(OutputIt out, const std::locale& loc, -- const S& format_str, Args&&... args) -> -- typename std::enable_if<enable, OutputIt>::type { -- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); -- return vformat_to(out, loc, to_string_view(format_str), vargs); --} -- --FMT_END_NAMESPACE -- --#endif // FMT_LOCALE_H_ -+#include "xchar.h" -+#warning fmt/locale.h is deprecated, include fmt/format.h or fmt/xchar.h instead -diff --git a/include/spdlog/fmt/bundled/os.h b/include/spdlog/fmt/bundled/os.h -index d44ea0c9..c447831e 100644 ---- a/include/spdlog/fmt/bundled/os.h -+++ b/include/spdlog/fmt/bundled/os.h -@@ -8,16 +8,12 @@ - #ifndef FMT_OS_H_ - #define FMT_OS_H_ - --#if defined(__MINGW32__) || defined(__CYGWIN__) --// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/. --# undef __STRICT_ANSI__ --#endif -- - #include <cerrno> --#include <clocale> // for locale_t -+#include <clocale> // locale_t - #include <cstddef> - #include <cstdio> --#include <cstdlib> // for strtod_l -+#include <cstdlib> // strtod_l -+#include <system_error> // std::system_error - - #if defined __APPLE__ || defined(__FreeBSD__) - # include <xlocale.h> // for LC_NUMERIC_MASK on OS X -@@ -74,6 +70,7 @@ - #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) - - FMT_BEGIN_NAMESPACE -+FMT_MODULE_EXPORT_BEGIN - - /** - \rst -@@ -122,19 +119,28 @@ template <typename Char> class basic_cstring_view { - using cstring_view = basic_cstring_view<char>; - using wcstring_view = basic_cstring_view<wchar_t>; - --// An error code. --class error_code { -- private: -- int value_; -- -- public: -- explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {} -+template <typename Char> struct formatter<std::error_code, Char> { -+ template <typename ParseContext> -+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { -+ return ctx.begin(); -+ } - -- int get() const FMT_NOEXCEPT { return value_; } -+ template <typename FormatContext> -+ FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const -+ -> decltype(ctx.out()) { -+ auto out = ctx.out(); -+ out = detail::write_bytes(out, ec.category().name(), -+ basic_format_specs<Char>()); -+ out = detail::write<Char>(out, Char(':')); -+ out = detail::write<Char>(out, ec.value()); -+ return out; -+ } - }; - - #ifdef _WIN32 --namespace detail { -+FMT_API const std::error_category& system_category() FMT_NOEXCEPT; -+ -+FMT_BEGIN_DETAIL_NAMESPACE - // A converter from UTF-16 to UTF-8. - // It is only provided for Windows since other systems support UTF-8 natively. - class utf16_to_utf8 { -@@ -143,7 +149,7 @@ class utf16_to_utf8 { - - public: - utf16_to_utf8() {} -- FMT_API explicit utf16_to_utf8(wstring_view s); -+ FMT_API explicit utf16_to_utf8(basic_string_view<wchar_t> s); - operator string_view() const { return string_view(&buffer_[0], size()); } - size_t size() const { return buffer_.size() - 1; } - const char* c_str() const { return &buffer_[0]; } -@@ -152,59 +158,68 @@ class utf16_to_utf8 { - // Performs conversion returning a system error code instead of - // throwing exception on conversion error. This method may still throw - // in case of memory allocation error. -- FMT_API int convert(wstring_view s); -+ FMT_API int convert(basic_string_view<wchar_t> s); - }; - - FMT_API void format_windows_error(buffer<char>& out, int error_code, -- string_view message) FMT_NOEXCEPT; --} // namespace detail -+ const char* message) FMT_NOEXCEPT; -+FMT_END_DETAIL_NAMESPACE - --/** A Windows error. */ --class windows_error : public system_error { -- private: -- FMT_API void init(int error_code, string_view format_str, format_args args); -+FMT_API std::system_error vwindows_error(int error_code, string_view format_str, -+ format_args args); - -- public: -- /** -- \rst -- Constructs a :class:`fmt::windows_error` object with the description -- of the form -- -- .. parsed-literal:: -- *<message>*: *<system-message>* -- -- where *<message>* is the formatted message and *<system-message>* is the -- system message corresponding to the error code. -- *error_code* is a Windows error code as given by ``GetLastError``. -- If *error_code* is not a valid error code such as -1, the system message -- will look like "error -1". -- -- **Example**:: -- -- // This throws a windows_error with the description -- // cannot open file 'madeup': The system cannot find the file specified. -- // or similar (system message may vary). -- const char *filename = "madeup"; -- LPOFSTRUCT of = LPOFSTRUCT(); -- HFILE file = OpenFile(filename, &of, OF_READ); -- if (file == HFILE_ERROR) { -- throw fmt::windows_error(GetLastError(), -- "cannot open file '{}'", filename); -- } -- \endrst -- */ -- template <typename... Args> -- windows_error(int error_code, string_view message, const Args&... args) { -- init(error_code, message, make_format_args(args...)); -- } --}; -+/** -+ \rst -+ Constructs a :class:`std::system_error` object with the description -+ of the form -+ -+ .. parsed-literal:: -+ *<message>*: *<system-message>* -+ -+ where *<message>* is the formatted message and *<system-message>* is the -+ system message corresponding to the error code. -+ *error_code* is a Windows error code as given by ``GetLastError``. -+ If *error_code* is not a valid error code such as -1, the system message -+ will look like "error -1". -+ -+ **Example**:: -+ -+ // This throws a system_error with the description -+ // cannot open file 'madeup': The system cannot find the file specified. -+ // or similar (system message may vary). -+ const char *filename = "madeup"; -+ LPOFSTRUCT of = LPOFSTRUCT(); -+ HFILE file = OpenFile(filename, &of, OF_READ); -+ if (file == HFILE_ERROR) { -+ throw fmt::windows_error(GetLastError(), -+ "cannot open file '{}'", filename); -+ } -+ \endrst -+*/ -+template <typename... Args> -+std::system_error windows_error(int error_code, string_view message, -+ const Args&... args) { -+ return vwindows_error(error_code, message, fmt::make_format_args(args...)); -+} - - // Reports a Windows error without throwing an exception. - // Can be used to report errors from destructors. - FMT_API void report_windows_error(int error_code, -- string_view message) FMT_NOEXCEPT; -+ const char* message) FMT_NOEXCEPT; -+#else -+inline const std::error_category& system_category() FMT_NOEXCEPT { -+ return std::system_category(); -+} - #endif // _WIN32 - -+// std::system is not available on some platforms such as iOS (#2248). -+#ifdef __OSX__ -+template <typename S, typename... Args, typename Char = char_t<S>> -+void say(const S& format_str, Args&&... args) { -+ std::system(format("say \"{}\"", format(format_str, args...)).c_str()); -+} -+#endif -+ - // A buffered file. - class buffered_file { - private: -@@ -255,7 +270,7 @@ class buffered_file { - - template <typename... Args> - inline void print(string_view format_str, const Args&... args) { -- vprint(format_str, make_format_args(args...)); -+ vprint(format_str, fmt::make_format_args(args...)); - } - }; - -@@ -280,7 +295,8 @@ class file { - WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. - RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing. - CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist. -- APPEND = FMT_POSIX(O_APPEND) // Open in append mode. -+ APPEND = FMT_POSIX(O_APPEND), // Open in append mode. -+ TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file. - }; - - // Constructs a file object which doesn't represent any file. -@@ -295,7 +311,8 @@ class file { - - file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; } - -- file& operator=(file&& other) FMT_NOEXCEPT { -+ // Move assignment is not noexcept because close may throw. -+ file& operator=(file&& other) { - close(); - fd_ = other.fd_; - other.fd_ = -1; -@@ -331,7 +348,7 @@ class file { - - // Makes fd be the copy of this file descriptor, closing fd first if - // necessary. -- FMT_API void dup2(int fd, error_code& ec) FMT_NOEXCEPT; -+ FMT_API void dup2(int fd, std::error_code& ec) FMT_NOEXCEPT; - - // Creates a pipe setting up read_end and write_end file objects for reading - // and writing respectively. -@@ -345,9 +362,10 @@ class file { - // Returns the memory page size. - long getpagesize(); - --namespace detail { -+FMT_BEGIN_DETAIL_NAMESPACE - - struct buffer_size { -+ buffer_size() = default; - size_t value = 0; - buffer_size operator=(size_t val) const { - auto bs = buffer_size(); -@@ -357,14 +375,14 @@ struct buffer_size { - }; - - struct ostream_params { -- int oflag = file::WRONLY | file::CREATE; -+ int oflag = file::WRONLY | file::CREATE | file::TRUNC; - size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; - - ostream_params() {} - - template <typename... T> -- ostream_params(T... params, int oflag) : ostream_params(params...) { -- this->oflag = oflag; -+ ostream_params(T... params, int new_oflag) : ostream_params(params...) { -+ oflag = new_oflag; - } - - template <typename... T> -@@ -373,12 +391,13 @@ struct ostream_params { - this->buffer_size = bs.value; - } - }; --} // namespace detail -+ -+FMT_END_DETAIL_NAMESPACE - - static constexpr detail::buffer_size buffer_size; - --// A fast output stream which is not thread-safe. --class ostream final : private detail::buffer<char> { -+/** A fast output stream which is not thread-safe. */ -+class FMT_API ostream final : private detail::buffer<char> { - private: - file file_; - -@@ -388,7 +407,7 @@ class ostream final : private detail::buffer<char> { - clear(); - } - -- FMT_API void grow(size_t) override final; -+ void grow(size_t) override; - - ostream(cstring_view path, const detail::ostream_params& params) - : file_(path, params.oflag) { -@@ -399,6 +418,7 @@ class ostream final : private detail::buffer<char> { - ostream(ostream&& other) - : detail::buffer<char>(other.data(), other.size(), other.capacity()), - file_(std::move(other.file_)) { -+ other.clear(); - other.set(nullptr, 0); - } - ~ostream() { -@@ -414,16 +434,30 @@ class ostream final : private detail::buffer<char> { - file_.close(); - } - -- template <typename S, typename... Args> -- void print(const S& format_str, const Args&... args) { -- format_to(detail::buffer_appender<char>(*this), format_str, args...); -+ /** -+ Formats ``args`` according to specifications in ``fmt`` and writes the -+ output to the file. -+ */ -+ template <typename... T> void print(format_string<T...> fmt, T&&... args) { -+ vformat_to(detail::buffer_appender<char>(*this), fmt, -+ fmt::make_format_args(args...)); - } - }; - - /** -- Opens a file for writing. Supported parameters passed in `params`: -- * ``<integer>``: Output flags (``file::WRONLY | file::CREATE`` by default) -+ \rst -+ Opens a file for writing. Supported parameters passed in *params*: -+ -+ * ``<integer>``: Flags passed to `open -+ <https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_ -+ (``file::WRONLY | file::CREATE`` by default) - * ``buffer_size=<integer>``: Output buffer size -+ -+ **Example**:: -+ -+ auto out = fmt::output_file("guide.txt"); -+ out.print("Don't {}", "Panic"); -+ \endrst - */ - template <typename... T> - inline ostream output_file(cstring_view path, T... params) { -@@ -475,6 +509,7 @@ class locale { - }; - using Locale FMT_DEPRECATED_ALIAS = locale; - #endif // FMT_LOCALE -+FMT_MODULE_EXPORT_END - FMT_END_NAMESPACE - - #endif // FMT_OS_H_ -diff --git a/include/spdlog/fmt/bundled/ostream.h b/include/spdlog/fmt/bundled/ostream.h -index 29c58ec1..d66248a6 100644 ---- a/include/spdlog/fmt/bundled/ostream.h -+++ b/include/spdlog/fmt/bundled/ostream.h -@@ -85,6 +85,8 @@ template <typename T, typename Char> class is_streamable { - using result = decltype(test<T>(0)); - - public: -+ is_streamable() = default; -+ - static const bool value = result::value; - }; - -@@ -149,6 +151,7 @@ struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>> - }; - } // namespace detail - -+FMT_MODULE_EXPORT - template <typename Char> - void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str, - basic_format_args<buffer_context<type_identity_t<Char>>> args) { -@@ -166,6 +169,7 @@ void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str, - fmt::print(cerr, "Don't {}!", "panic"); - \endrst - */ -+FMT_MODULE_EXPORT - template <typename S, typename... Args, - typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>> - void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) { -diff --git a/include/spdlog/fmt/bundled/posix.h b/include/spdlog/fmt/bundled/posix.h -deleted file mode 100644 -index da19e9d5..00000000 ---- a/include/spdlog/fmt/bundled/posix.h -+++ /dev/null -@@ -1,2 +0,0 @@ --#include "os.h" --#warning "fmt/posix.h is deprecated; use fmt/os.h instead" -diff --git a/include/spdlog/fmt/bundled/printf.h b/include/spdlog/fmt/bundled/printf.h -index 8c28ac23..3a3cd152 100644 ---- a/include/spdlog/fmt/bundled/printf.h -+++ b/include/spdlog/fmt/bundled/printf.h -@@ -10,11 +10,54 @@ - - #include <algorithm> // std::max - #include <limits> // std::numeric_limits -+#include <ostream> - --#include "ostream.h" -+#include "format.h" - - FMT_BEGIN_NAMESPACE --namespace detail { -+FMT_MODULE_EXPORT_BEGIN -+ -+template <typename T> struct printf_formatter { printf_formatter() = delete; }; -+ -+template <typename Char> -+class basic_printf_parse_context : public basic_format_parse_context<Char> { -+ using basic_format_parse_context<Char>::basic_format_parse_context; -+}; -+ -+template <typename OutputIt, typename Char> class basic_printf_context { -+ private: -+ OutputIt out_; -+ basic_format_args<basic_printf_context> args_; -+ -+ public: -+ using char_type = Char; -+ using format_arg = basic_format_arg<basic_printf_context>; -+ using parse_context_type = basic_printf_parse_context<Char>; -+ template <typename T> using formatter_type = printf_formatter<T>; -+ -+ /** -+ \rst -+ Constructs a ``printf_context`` object. References to the arguments are -+ stored in the context object so make sure they have appropriate lifetimes. -+ \endrst -+ */ -+ basic_printf_context(OutputIt out, -+ basic_format_args<basic_printf_context> args) -+ : out_(out), args_(args) {} -+ -+ OutputIt out() { return out_; } -+ void advance_to(OutputIt it) { out_ = it; } -+ -+ detail::locale_ref locale() { return {}; } -+ -+ format_arg arg(int id) const { return args_.get(id); } -+ -+ FMT_CONSTEXPR void on_error(const char* message) { -+ detail::error_handler().on_error(message); -+ } -+}; -+ -+FMT_BEGIN_DETAIL_NAMESPACE - - // Checks if a value fits in int - used to avoid warnings about comparing - // signed and unsigned integers. -@@ -178,79 +221,34 @@ template <typename Char> class printf_width_handler { - } - }; - --template <typename Char, typename Context> --void vprintf(buffer<Char>& buf, basic_string_view<Char> format, -- basic_format_args<Context> args) { -- Context(buffer_appender<Char>(buf), format, args).format(); --} --} // namespace detail -- --// For printing into memory_buffer. --template <typename Char, typename Context> --FMT_DEPRECATED void printf(detail::buffer<Char>& buf, -- basic_string_view<Char> format, -- basic_format_args<Context> args) { -- return detail::vprintf(buf, format, args); --} --using detail::vprintf; -- --template <typename Char> --class basic_printf_parse_context : public basic_format_parse_context<Char> { -- using basic_format_parse_context<Char>::basic_format_parse_context; --}; --template <typename OutputIt, typename Char> class basic_printf_context; -- --/** -- \rst -- The ``printf`` argument formatter. -- \endrst -- */ -+// The ``printf`` argument formatter. - template <typename OutputIt, typename Char> --class printf_arg_formatter : public detail::arg_formatter_base<OutputIt, Char> { -- public: -- using iterator = OutputIt; -- -+class printf_arg_formatter : public arg_formatter<Char> { - private: -- using char_type = Char; -- using base = detail::arg_formatter_base<OutputIt, Char>; -+ using base = arg_formatter<Char>; - using context_type = basic_printf_context<OutputIt, Char>; -+ using format_specs = basic_format_specs<Char>; - - context_type& context_; - -- void write_null_pointer(char) { -- this->specs()->type = 0; -- this->write("(nil)"); -- } -- -- void write_null_pointer(wchar_t) { -- this->specs()->type = 0; -- this->write(L"(nil)"); -+ OutputIt write_null_pointer(bool is_string = false) { -+ auto s = this->specs; -+ s.type = 0; -+ return write_bytes(this->out, is_string ? "(null)" : "(nil)", s); - } - - public: -- using format_specs = typename base::format_specs; -+ printf_arg_formatter(OutputIt iter, format_specs& s, context_type& ctx) -+ : base{iter, s, locale_ref()}, context_(ctx) {} - -- /** -- \rst -- Constructs an argument formatter object. -- *buffer* is a reference to the output buffer and *specs* contains format -- specifier information for standard argument types. -- \endrst -- */ -- printf_arg_formatter(iterator iter, format_specs& specs, context_type& ctx) -- : base(iter, &specs, detail::locale_ref()), context_(ctx) {} -- -- template <typename T, FMT_ENABLE_IF(fmt::detail::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) { -- format_specs& fmt_specs = *this->specs(); -- if (fmt_specs.type != 's') return base::operator()(value ? 1 : 0); -- fmt_specs.type = 0; -- this->write(value != 0); -- } else if (std::is_same<T, char_type>::value) { -- format_specs& fmt_specs = *this->specs(); -+ OutputIt operator()(monostate value) { return base::operator()(value); } -+ -+ template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)> -+ OutputIt operator()(T value) { -+ // MSVC2013 fails to compile separate overloads for bool and Char so use -+ // std::is_same instead. -+ if (std::is_same<T, Char>::value) { -+ format_specs fmt_specs = this->specs; - if (fmt_specs.type && fmt_specs.type != 'c') - return (*this)(static_cast<int>(value)); - fmt_specs.sign = sign::none; -@@ -260,138 +258,49 @@ class printf_arg_formatter : public detail::arg_formatter_base<OutputIt, Char> { - // ignored for non-numeric types - if (fmt_specs.align == align::none || fmt_specs.align == align::numeric) - fmt_specs.align = align::right; -- return base::operator()(value); -- } else { -- return base::operator()(value); -+ return write<Char>(this->out, static_cast<Char>(value), fmt_specs); - } -- return this->out(); -+ return base::operator()(value); - } - - template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> -- iterator operator()(T value) { -+ OutputIt operator()(T value) { - return base::operator()(value); - } - - /** Formats a null-terminated C string. */ -- iterator operator()(const char* value) { -- if (value) -- base::operator()(value); -- else if (this->specs()->type == 'p') -- write_null_pointer(char_type()); -- else -- this->write("(null)"); -- return this->out(); -+ OutputIt operator()(const char* value) { -+ if (value) return base::operator()(value); -+ return write_null_pointer(this->specs.type != 'p'); - } - - /** Formats a null-terminated wide C string. */ -- iterator operator()(const wchar_t* value) { -- if (value) -- base::operator()(value); -- else if (this->specs()->type == 'p') -- write_null_pointer(char_type()); -- else -- this->write(L"(null)"); -- return this->out(); -+ OutputIt operator()(const wchar_t* value) { -+ if (value) return base::operator()(value); -+ return write_null_pointer(this->specs.type != 'p'); - } - -- iterator operator()(basic_string_view<char_type> value) { -+ OutputIt operator()(basic_string_view<Char> value) { - return base::operator()(value); - } - -- iterator operator()(monostate value) { return base::operator()(value); } -- - /** Formats a pointer. */ -- iterator operator()(const void* value) { -- if (value) return base::operator()(value); -- this->specs()->type = 0; -- write_null_pointer(char_type()); -- return this->out(); -+ OutputIt operator()(const void* value) { -+ return value ? base::operator()(value) : write_null_pointer(); - } - - /** Formats an argument of a custom (user-defined) type. */ -- iterator operator()(typename basic_format_arg<context_type>::handle handle) { -- handle.format(context_.parse_context(), context_); -- return this->out(); -+ OutputIt operator()(typename basic_format_arg<context_type>::handle handle) { -+ auto parse_ctx = -+ basic_printf_parse_context<Char>(basic_string_view<Char>()); -+ handle.format(parse_ctx, context_); -+ return this->out; - } - }; - --template <typename T> struct printf_formatter { -- printf_formatter() = delete; -- -- template <typename ParseContext> -- auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { -- return ctx.begin(); -- } -- -- template <typename FormatContext> -- auto format(const T& value, FormatContext& ctx) -> decltype(ctx.out()) { -- detail::format_value(detail::get_container(ctx.out()), value); -- return ctx.out(); -- } --}; -- --/** -- This template formats data and writes the output through an output iterator. -- */ --template <typename OutputIt, typename Char> class basic_printf_context { -- public: -- /** The character type for the output. */ -- using char_type = Char; -- using iterator = OutputIt; -- using format_arg = basic_format_arg<basic_printf_context>; -- using parse_context_type = basic_printf_parse_context<Char>; -- template <typename T> using formatter_type = printf_formatter<T>; -- -- private: -- using format_specs = basic_format_specs<char_type>; -- -- OutputIt out_; -- basic_format_args<basic_printf_context> args_; -- parse_context_type parse_ctx_; -- -- static void parse_flags(format_specs& specs, const Char*& it, -- const Char* end); -- -- // Returns the argument with specified index or, if arg_index is -1, the next -- // argument. -- format_arg get_arg(int arg_index = -1); -- -- // Parses argument index, flags and width and returns the argument index. -- int parse_header(const Char*& it, const Char* end, format_specs& specs); -- -- public: -- /** -- \rst -- Constructs a ``printf_context`` object. References to the arguments are -- stored in the context object so make sure they have appropriate lifetimes. -- \endrst -- */ -- basic_printf_context(OutputIt out, basic_string_view<char_type> format_str, -- basic_format_args<basic_printf_context> args) -- : out_(out), args_(args), parse_ctx_(format_str) {} -- -- OutputIt out() { return out_; } -- void advance_to(OutputIt it) { out_ = it; } -- -- detail::locale_ref locale() { return {}; } -- -- format_arg arg(int id) const { return args_.get(id); } -- -- parse_context_type& parse_context() { return parse_ctx_; } -- -- FMT_CONSTEXPR void on_error(const char* message) { -- parse_ctx_.on_error(message); -- } -- -- /** Formats stored arguments and writes the output to the range. */ -- template <typename ArgFormatter = printf_arg_formatter<OutputIt, Char>> -- OutputIt format(); --}; -- --template <typename OutputIt, typename Char> --void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs, -- const Char*& it, -- const Char* end) { -+template <typename Char> -+void parse_flags(basic_format_specs<Char>& specs, const Char*& it, -+ const Char* end) { - for (; it != end; ++it) { - switch (*it) { - case '-': -@@ -417,35 +326,24 @@ void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs, - } - } - --template <typename OutputIt, typename Char> --typename basic_printf_context<OutputIt, Char>::format_arg --basic_printf_context<OutputIt, Char>::get_arg(int arg_index) { -- if (arg_index < 0) -- arg_index = parse_ctx_.next_arg_id(); -- else -- parse_ctx_.check_arg_id(--arg_index); -- return detail::get_arg(*this, arg_index); --} -- --template <typename OutputIt, typename Char> --int basic_printf_context<OutputIt, Char>::parse_header(const Char*& it, -- const Char* end, -- format_specs& specs) { -+template <typename Char, typename GetArg> -+int parse_header(const Char*& it, const Char* end, -+ basic_format_specs<Char>& specs, GetArg get_arg) { - int arg_index = -1; -- char_type c = *it; -+ Char c = *it; - if (c >= '0' && c <= '9') { - // Parse an argument index (if followed by '$') or a width possibly - // preceded with '0' flag(s). -- detail::error_handler eh; -- int value = parse_nonnegative_int(it, end, eh); -+ int value = parse_nonnegative_int(it, end, -1); - if (it != end && *it == '$') { // value is an argument index - ++it; -- arg_index = value; -+ arg_index = value != -1 ? value : max_value<int>(); - } else { - if (c == '0') specs.fill[0] = '0'; - if (value != 0) { - // Nonzero value means that we parsed width and don't need to - // parse it or flags again, so return now. -+ if (value == -1) FMT_THROW(format_error("number is too big")); - specs.width = value; - return arg_index; - } -@@ -455,58 +353,76 @@ int basic_printf_context<OutputIt, Char>::parse_header(const Char*& it, - // Parse width. - if (it != end) { - if (*it >= '0' && *it <= '9') { -- detail::error_handler eh; -- specs.width = parse_nonnegative_int(it, end, eh); -+ specs.width = parse_nonnegative_int(it, end, -1); -+ if (specs.width == -1) FMT_THROW(format_error("number is too big")); - } else if (*it == '*') { - ++it; - specs.width = static_cast<int>(visit_format_arg( -- detail::printf_width_handler<char_type>(specs), get_arg())); -+ detail::printf_width_handler<Char>(specs), get_arg(-1))); - } - } - return arg_index; - } - --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(); -+template <typename Char, typename Context> -+void vprintf(buffer<Char>& buf, basic_string_view<Char> format, -+ basic_format_args<Context> args) { -+ using OutputIt = buffer_appender<Char>; -+ auto out = OutputIt(buf); -+ auto context = basic_printf_context<OutputIt, Char>(out, args); -+ auto parse_ctx = basic_printf_parse_context<Char>(format); -+ -+ // Returns the argument with specified index or, if arg_index is -1, the next -+ // argument. -+ auto get_arg = [&](int arg_index) { -+ if (arg_index < 0) -+ arg_index = parse_ctx.next_arg_id(); -+ else -+ parse_ctx.check_arg_id(--arg_index); -+ return detail::get_arg(context, arg_index); -+ }; -+ -+ const Char* start = parse_ctx.begin(); -+ const Char* end = parse_ctx.end(); - auto it = start; - while (it != end) { -- char_type c = *it++; -- if (c != '%') continue; -+ if (!detail::find<false, Char>(it, end, '%', it)) { -+ it = end; // detail::find leaves it == nullptr if it doesn't find '%' -+ break; -+ } -+ Char c = *it++; - if (it != end && *it == c) { -- out = std::copy(start, it, out); -+ out = detail::write( -+ out, basic_string_view<Char>(start, detail::to_unsigned(it - start))); - start = ++it; - continue; - } -- out = std::copy(start, it - 1, out); -+ out = detail::write(out, basic_string_view<Char>( -+ start, detail::to_unsigned(it - 1 - start))); - -- format_specs specs; -+ basic_format_specs<Char> specs; - specs.align = align::right; - - // Parse argument index, flags and width. -- int arg_index = parse_header(it, end, specs); -- if (arg_index == 0) on_error("argument not found"); -+ int arg_index = parse_header(it, end, specs, get_arg); -+ if (arg_index == 0) parse_ctx.on_error("argument not found"); - - // Parse precision. - if (it != end && *it == '.') { - ++it; - c = it != end ? *it : 0; - if ('0' <= c && c <= '9') { -- detail::error_handler eh; -- specs.precision = parse_nonnegative_int(it, end, eh); -+ specs.precision = parse_nonnegative_int(it, end, 0); - } else if (c == '*') { - ++it; - specs.precision = static_cast<int>( -- visit_format_arg(detail::printf_precision_handler(), get_arg())); -+ visit_format_arg(detail::printf_precision_handler(), get_arg(-1))); - } else { - specs.precision = 0; - } - } - -- format_arg arg = get_arg(arg_index); -+ auto arg = get_arg(arg_index); - // For d, i, o, u, x, and X conversion specifiers, if a precision is - // specified, the '0' flag is ignored - if (specs.precision >= 0 && arg.is_integral()) -@@ -516,9 +432,10 @@ OutputIt basic_printf_context<OutputIt, Char>::format() { - auto str = visit_format_arg(detail::get_cstring<Char>(), arg); - auto str_end = str + specs.precision; - auto nul = std::find(str, str_end, Char()); -- arg = detail::make_arg<basic_printf_context>(basic_string_view<Char>( -- str, -- detail::to_unsigned(nul != str_end ? nul - str : specs.precision))); -+ arg = detail::make_arg<basic_printf_context<OutputIt, Char>>( -+ basic_string_view<Char>( -+ str, detail::to_unsigned(nul != str_end ? nul - str -+ : specs.precision))); - } - if (specs.alt && visit_format_arg(detail::is_zero_int(), arg)) - specs.alt = false; -@@ -532,7 +449,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() { - - // Parse length and convert the argument to the required type. - c = it != end ? *it++ : 0; -- char_type t = it != end ? *it : 0; -+ Char t = it != end ? *it : 0; - using detail::convert_arg; - switch (c) { - case 'h': -@@ -582,8 +499,9 @@ OutputIt basic_printf_context<OutputIt, Char>::format() { - specs.type = 'd'; - break; - case 'c': -- visit_format_arg(detail::char_converter<basic_printf_context>(arg), -- arg); -+ visit_format_arg( -+ detail::char_converter<basic_printf_context<OutputIt, Char>>(arg), -+ arg); - break; - } - } -@@ -591,10 +509,12 @@ OutputIt basic_printf_context<OutputIt, Char>::format() { - start = it; - - // Format argument. -- out = visit_format_arg(ArgFormatter(out, specs, *this), arg); -+ out = visit_format_arg( -+ detail::printf_arg_formatter<OutputIt, Char>(out, specs, context), arg); - } -- return std::copy(start, it, out); -+ detail::write(out, basic_string_view<Char>(start, to_unsigned(it - start))); - } -+FMT_END_DETAIL_NAMESPACE - - template <typename Char> - using basic_printf_context_t = -@@ -612,9 +532,9 @@ using wprintf_args = basic_format_args<wprintf_context>; - arguments and can be implicitly converted to `~fmt::printf_args`. - \endrst - */ --template <typename... Args> --inline format_arg_store<printf_context, Args...> make_printf_args( -- const Args&... args) { -+template <typename... T> -+inline auto make_printf_args(const T&... args) -+ -> format_arg_store<printf_context, T...> { - return {args...}; - } - -@@ -624,18 +544,19 @@ inline format_arg_store<printf_context, Args...> make_printf_args( - arguments and can be implicitly converted to `~fmt::wprintf_args`. - \endrst - */ --template <typename... Args> --inline format_arg_store<wprintf_context, Args...> make_wprintf_args( -- const Args&... args) { -+template <typename... T> -+inline auto make_wprintf_args(const T&... args) -+ -> format_arg_store<wprintf_context, T...> { - return {args...}; - } - - template <typename S, typename Char = char_t<S>> --inline std::basic_string<Char> vsprintf( -- const S& format, -- basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) { -+inline auto vsprintf( -+ const S& fmt, -+ basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) -+ -> std::basic_string<Char> { - basic_memory_buffer<Char> buffer; -- vprintf(buffer, to_string_view(format), args); -+ vprintf(buffer, to_string_view(fmt), args); - return to_string(buffer); - } - -@@ -648,19 +569,20 @@ inline std::basic_string<Char> vsprintf( - std::string message = fmt::sprintf("The answer is %d", 42); - \endrst - */ --template <typename S, typename... Args, -+template <typename S, typename... T, - typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>> --inline std::basic_string<Char> sprintf(const S& format, const Args&... args) { -+inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> { - using context = basic_printf_context_t<Char>; -- return vsprintf(to_string_view(format), make_format_args<context>(args...)); -+ return vsprintf(to_string_view(fmt), fmt::make_format_args<context>(args...)); - } - - template <typename S, typename Char = char_t<S>> --inline int vfprintf( -- std::FILE* f, const S& format, -- basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) { -+inline auto vfprintf( -+ std::FILE* f, const S& fmt, -+ basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) -+ -> int { - basic_memory_buffer<Char> buffer; -- vprintf(buffer, to_string_view(format), args); -+ vprintf(buffer, to_string_view(fmt), args); - size_t size = buffer.size(); - return std::fwrite(buffer.data(), sizeof(Char), size, f) < size - ? -1 -@@ -676,19 +598,19 @@ inline int vfprintf( - fmt::fprintf(stderr, "Don't %s!", "panic"); - \endrst - */ --template <typename S, typename... Args, -- typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>> --inline int fprintf(std::FILE* f, const S& format, const Args&... args) { -+template <typename S, typename... T, typename Char = char_t<S>> -+inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int { - using context = basic_printf_context_t<Char>; -- return vfprintf(f, to_string_view(format), -- make_format_args<context>(args...)); -+ return vfprintf(f, to_string_view(fmt), -+ fmt::make_format_args<context>(args...)); - } - - template <typename S, typename Char = char_t<S>> --inline int vprintf( -- const S& format, -- basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) { -- return vfprintf(stdout, to_string_view(format), args); -+inline auto vprintf( -+ const S& fmt, -+ basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) -+ -> int { -+ return vfprintf(stdout, to_string_view(fmt), args); - } - - /** -@@ -700,52 +622,31 @@ inline int vprintf( - fmt::printf("Elapsed time: %.2f seconds", 1.23); - \endrst - */ --template <typename S, typename... Args, -- FMT_ENABLE_IF(detail::is_string<S>::value)> --inline int printf(const S& format_str, const Args&... args) { -- using context = basic_printf_context_t<char_t<S>>; -- return vprintf(to_string_view(format_str), -- make_format_args<context>(args...)); -+template <typename S, typename... T, FMT_ENABLE_IF(detail::is_string<S>::value)> -+inline auto printf(const S& fmt, const T&... args) -> int { -+ return vprintf( -+ to_string_view(fmt), -+ fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...)); - } - - template <typename S, typename Char = char_t<S>> --inline int vfprintf( -- std::basic_ostream<Char>& os, const S& format, -- basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) { -+FMT_DEPRECATED auto vfprintf( -+ std::basic_ostream<Char>& os, const S& fmt, -+ basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) -+ -> int { - basic_memory_buffer<Char> buffer; -- vprintf(buffer, to_string_view(format), args); -- detail::write_buffer(os, buffer); -+ vprintf(buffer, to_string_view(fmt), args); -+ os.write(buffer.data(), static_cast<std::streamsize>(buffer.size())); - 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( -- detail::buffer<Char>& out, basic_string_view<Char> format_str, -- basic_format_args<type_identity_t<Context>> args) { -- typename ArgFormatter::iterator iter(out); -- Context(iter, format_str, args).template format<ArgFormatter>(); -- return iter; -+template <typename S, typename... T, typename Char = char_t<S>> -+FMT_DEPRECATED auto fprintf(std::basic_ostream<Char>& os, const S& fmt, -+ const T&... args) -> int { -+ return vfprintf(os, to_string_view(fmt), -+ fmt::make_format_args<basic_printf_context_t<Char>>(args...)); - } - --/** -- \rst -- Prints formatted data to the stream *os*. -- -- **Example**:: -- -- fmt::fprintf(cerr, "Don't %s!", "panic"); -- \endrst -- */ --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) { -- using context = basic_printf_context_t<Char>; -- return vfprintf(os, to_string_view(format_str), -- make_format_args<context>(args...)); --} -+FMT_MODULE_EXPORT_END - FMT_END_NAMESPACE - - #endif // FMT_PRINTF_H_ -diff --git a/include/spdlog/fmt/bundled/ranges.h b/include/spdlog/fmt/bundled/ranges.h -index 632f0494..52961389 100644 ---- a/include/spdlog/fmt/bundled/ranges.h -+++ b/include/spdlog/fmt/bundled/ranges.h -@@ -17,41 +17,31 @@ - - #include "format.h" - --// output only up to N items from the range. --#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT --# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256 --#endif -- - FMT_BEGIN_NAMESPACE - --template <typename Char> struct formatting_base { -+template <typename Char, typename Enable = void> struct formatting_range { -+#ifdef FMT_DEPRECATED_BRACED_RANGES -+ Char prefix = '{'; -+ Char postfix = '}'; -+#else -+ Char prefix = '['; -+ Char postfix = ']'; -+#endif -+ - template <typename ParseContext> - FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return ctx.begin(); - } - }; - --template <typename Char, typename Enable = void> --struct formatting_range : formatting_base<Char> { -- static FMT_CONSTEXPR_DECL const size_t range_length_limit = -- FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the -- // range. -- Char prefix; -- Char delimiter; -- Char postfix; -- formatting_range() : prefix('{'), delimiter(','), postfix('}') {} -- static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; -- static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; --}; -+template <typename Char, typename Enable = void> struct formatting_tuple { -+ Char prefix = '('; -+ Char postfix = ')'; - --template <typename Char, typename Enable = void> --struct formatting_tuple : formatting_base<Char> { -- Char prefix; -- Char delimiter; -- Char postfix; -- formatting_tuple() : prefix('('), delimiter(','), postfix(')') {} -- static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; -- static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; -+ template <typename ParseContext> -+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { -+ return ctx.begin(); -+ } - }; - - namespace detail { -@@ -75,8 +65,14 @@ OutputIterator copy(char ch, OutputIterator out) { - return out; - } - -+template <typename OutputIterator> -+OutputIterator copy(wchar_t ch, OutputIterator out) { -+ *out++ = ch; -+ return out; -+} -+ - /// Return true value if T has std::string interface, like std::string_view. --template <typename T> class is_like_std_string { -+template <typename T> class is_std_string_like { - template <typename U> - static auto check(U* p) - -> decltype((void)p->find('a'), p->length(), (void)p->data(), int()); -@@ -88,19 +84,107 @@ template <typename T> class is_like_std_string { - }; - - template <typename Char> --struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {}; -+struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {}; - - template <typename... Ts> struct conditional_helper {}; - - template <typename T, typename _ = void> struct is_range_ : std::false_type {}; - - #if !FMT_MSC_VER || FMT_MSC_VER > 1800 -+ -+# define FMT_DECLTYPE_RETURN(val) \ -+ ->decltype(val) { return val; } \ -+ static_assert( \ -+ true, "") // This makes it so that a semicolon is required after the -+ // macro, which helps clang-format handle the formatting. -+ -+// C array overload -+template <typename T, std::size_t N> -+auto range_begin(const T (&arr)[N]) -> const T* { -+ return arr; -+} -+template <typename T, std::size_t N> -+auto range_end(const T (&arr)[N]) -> const T* { -+ return arr + N; -+} -+ -+template <typename T, typename Enable = void> -+struct has_member_fn_begin_end_t : std::false_type {}; -+ -+template <typename T> -+struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()), -+ decltype(std::declval<T>().end())>> -+ : std::true_type {}; -+ -+// Member function overload -+template <typename T> -+auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin()); -+template <typename T> -+auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end()); -+ -+// ADL overload. Only participates in overload resolution if member functions -+// are not found. -+template <typename T> -+auto range_begin(T&& rng) -+ -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value, -+ decltype(begin(static_cast<T&&>(rng)))> { -+ return begin(static_cast<T&&>(rng)); -+} -+template <typename T> -+auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value, -+ decltype(end(static_cast<T&&>(rng)))> { -+ return end(static_cast<T&&>(rng)); -+} -+ -+template <typename T, typename Enable = void> -+struct has_const_begin_end : std::false_type {}; -+template <typename T, typename Enable = void> -+struct has_mutable_begin_end : std::false_type {}; -+ - template <typename T> --struct is_range_< -- T, conditional_t<false, -- conditional_helper<decltype(std::declval<T>().begin()), -- decltype(std::declval<T>().end())>, -- void>> : std::true_type {}; -+struct has_const_begin_end< -+ T, void_t<decltype(detail::range_begin( -+ std::declval<const remove_cvref_t<T>&>())), -+ decltype(detail::range_begin( -+ std::declval<const remove_cvref_t<T>&>()))>> -+ : std::true_type {}; -+ -+template <typename T> -+struct has_mutable_begin_end< -+ T, void_t<decltype(detail::range_begin(std::declval<T>())), -+ decltype(detail::range_begin(std::declval<T>())), -+ enable_if_t<std::is_copy_constructible<T>::value>>> -+ : std::true_type {}; -+ -+template <typename T> -+struct is_range_<T, void> -+ : std::integral_constant<bool, (has_const_begin_end<T>::value || -+ has_mutable_begin_end<T>::value)> {}; -+ -+template <typename T, typename Enable = void> struct range_to_view; -+template <typename T> -+struct range_to_view<T, enable_if_t<has_const_begin_end<T>::value>> { -+ struct view_t { -+ const T* m_range_ptr; -+ -+ auto begin() const FMT_DECLTYPE_RETURN(detail::range_begin(*m_range_ptr)); -+ auto end() const FMT_DECLTYPE_RETURN(detail::range_end(*m_range_ptr)); -+ }; -+ static auto view(const T& range) -> view_t { return {&range}; } -+}; -+ -+template <typename T> -+struct range_to_view<T, enable_if_t<!has_const_begin_end<T>::value && -+ has_mutable_begin_end<T>::value>> { -+ struct view_t { -+ T m_range_copy; -+ -+ auto begin() FMT_DECLTYPE_RETURN(detail::range_begin(m_range_copy)); -+ auto end() FMT_DECLTYPE_RETURN(detail::range_end(m_range_copy)); -+ }; -+ static auto view(const T& range) -> view_t { return {range}; } -+}; -+# undef FMT_DECLTYPE_RETURN - #endif - - /// tuple_size and tuple_element check. -@@ -158,33 +242,42 @@ template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) { - } - - template <typename Range> --using value_type = remove_cvref_t<decltype(*std::declval<Range>().begin())>; -+using value_type = -+ remove_cvref_t<decltype(*detail::range_begin(std::declval<Range>()))>; - --template <typename Arg, FMT_ENABLE_IF(!is_like_std_string< -- typename std::decay<Arg>::type>::value)> --FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) { -- return add_space ? " {}" : "{}"; -+template <typename OutputIt> OutputIt write_delimiter(OutputIt out) { -+ *out++ = ','; -+ *out++ = ' '; -+ return out; - } - --template <typename Arg, FMT_ENABLE_IF(is_like_std_string< -- typename std::decay<Arg>::type>::value)> --FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) { -- return add_space ? " \"{}\"" : "\"{}\""; -+template < -+ typename Char, typename OutputIt, typename Arg, -+ FMT_ENABLE_IF(is_std_string_like<typename std::decay<Arg>::type>::value)> -+OutputIt write_range_entry(OutputIt out, const Arg& v) { -+ *out++ = '"'; -+ out = write<Char>(out, v); -+ *out++ = '"'; -+ return out; - } - --FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) { -- return add_space ? " \"{}\"" : "\"{}\""; --} --FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) { -- return add_space ? L" \"{}\"" : L"\"{}\""; -+template <typename Char, typename OutputIt, typename Arg, -+ FMT_ENABLE_IF(std::is_same<Arg, Char>::value)> -+OutputIt write_range_entry(OutputIt out, const Arg v) { -+ *out++ = '\''; -+ *out++ = v; -+ *out++ = '\''; -+ return out; - } - --FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) { -- return add_space ? " '{}'" : "'{}'"; --} --FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) { -- return add_space ? L" '{}'" : L"'{}'"; -+template < -+ typename Char, typename OutputIt, typename Arg, -+ FMT_ENABLE_IF(!is_std_string_like<typename std::decay<Arg>::type>::value && -+ !std::is_same<Arg, Char>::value)> -+OutputIt write_range_entry(OutputIt out, const Arg& v) { -+ return write<Char>(out, v); - } -+ - } // namespace detail - - template <typename T> struct is_tuple_like { -@@ -198,23 +291,14 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> { - // C++11 generic lambda for format() - template <typename FormatContext> struct format_each { - template <typename T> void operator()(const T& v) { -- if (i > 0) { -- if (formatting.add_prepostfix_space) { -- *out++ = ' '; -- } -- out = detail::copy(formatting.delimiter, out); -- } -- out = format_to(out, -- detail::format_str_quoted( -- (formatting.add_delimiter_spaces && i > 0), v), -- v); -+ if (i > 0) out = detail::write_delimiter(out); -+ out = detail::write_range_entry<Char>(out, v); - ++i; - } -- - formatting_tuple<Char>& formatting; - size_t& i; -- typename std::add_lvalue_reference<decltype( -- std::declval<FormatContext>().out())>::type out; -+ typename std::add_lvalue_reference< -+ decltype(std::declval<FormatContext>().out())>::type out; - }; - - public: -@@ -229,12 +313,9 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> { - auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) { - auto out = ctx.out(); - size_t i = 0; -- detail::copy(formatting.prefix, out); - -+ detail::copy(formatting.prefix, out); - detail::for_each(values, format_each<FormatContext>{formatting, i, out}); -- if (formatting.add_prepostfix_space) { -- *out++ = ' '; -- } - detail::copy(formatting.postfix, out); - - return ctx.out(); -@@ -243,7 +324,7 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> { - - template <typename T, typename Char> struct is_range { - static FMT_CONSTEXPR_DECL const bool value = -- detail::is_range_<T>::value && !detail::is_like_std_string<T>::value && -+ detail::is_range_<T>::value && !detail::is_std_string_like<T>::value && - !std::is_convertible<T, std::basic_string<Char>>::value && - !std::is_constructible<detail::std_string_view<Char>, T>::value; - }; -@@ -251,15 +332,14 @@ template <typename T, typename Char> struct is_range { - template <typename T, typename Char> - struct formatter< - T, Char, -- enable_if_t<fmt::is_range<T, Char>::value -+ enable_if_t< -+ fmt::is_range<T, Char>::value - // Workaround a bug in MSVC 2017 and earlier. - #if !FMT_MSC_VER || FMT_MSC_VER >= 1927 -- && -- (has_formatter<detail::value_type<T>, format_context>::value || -- detail::has_fallback_formatter<detail::value_type<T>, -- format_context>::value) -+ && (has_formatter<detail::value_type<T>, format_context>::value || -+ detail::has_fallback_formatter<detail::value_type<T>, Char>::value) - #endif -- >> { -+ >> { - formatting_range<Char> formatting; - - template <typename ParseContext> -@@ -271,71 +351,64 @@ struct formatter< - typename FormatContext::iterator format(const T& values, FormatContext& ctx) { - auto out = detail::copy(formatting.prefix, ctx.out()); - size_t i = 0; -- auto it = values.begin(); -- auto end = values.end(); -+ auto view = detail::range_to_view<T>::view(values); -+ auto it = view.begin(); -+ auto end = view.end(); - for (; it != end; ++it) { -- if (i > 0) { -- if (formatting.add_prepostfix_space) *out++ = ' '; -- out = detail::copy(formatting.delimiter, out); -- } -- out = format_to(out, -- detail::format_str_quoted( -- (formatting.add_delimiter_spaces && i > 0), *it), -- *it); -- if (++i > formatting.range_length_limit) { -- out = format_to(out, " ... <other elements>"); -- break; -- } -+ if (i > 0) out = detail::write_delimiter(out); -+ out = detail::write_range_entry<Char>(out, *it); -+ ++i; - } -- if (formatting.add_prepostfix_space) *out++ = ' '; - return detail::copy(formatting.postfix, out); - } - }; - --template <typename Char, typename... T> struct tuple_arg_join : detail::view { -+template <typename Char, typename... T> struct tuple_join_view : detail::view { - const std::tuple<T...>& tuple; - basic_string_view<Char> sep; - -- tuple_arg_join(const std::tuple<T...>& t, basic_string_view<Char> s) -- : tuple{t}, sep{s} {} -+ tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s) -+ : tuple(t), sep{s} {} - }; - - template <typename Char, typename... T> --struct formatter<tuple_arg_join<Char, T...>, Char> { -+using tuple_arg_join = tuple_join_view<Char, T...>; -+ -+template <typename Char, typename... T> -+struct formatter<tuple_join_view<Char, T...>, Char> { - template <typename ParseContext> - FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return ctx.begin(); - } - - template <typename FormatContext> -- typename FormatContext::iterator format( -- const tuple_arg_join<Char, T...>& value, FormatContext& ctx) { -+ auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx) -> -+ typename FormatContext::iterator { - return format(value, ctx, detail::make_index_sequence<sizeof...(T)>{}); - } - - private: - template <typename FormatContext, size_t... N> -- typename FormatContext::iterator format( -- const tuple_arg_join<Char, T...>& value, FormatContext& ctx, -- detail::index_sequence<N...>) { -+ auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx, -+ detail::index_sequence<N...>) -> -+ typename FormatContext::iterator { - return format_args(value, ctx, std::get<N>(value.tuple)...); - } - - template <typename FormatContext> -- typename FormatContext::iterator format_args( -- const tuple_arg_join<Char, T...>&, FormatContext& ctx) { -+ auto format_args(const tuple_join_view<Char, T...>&, FormatContext& ctx) -> -+ typename FormatContext::iterator { - // NOTE: for compilers that support C++17, this empty function instantiation - // can be replaced with a constexpr branch in the variadic overload. - return ctx.out(); - } - - template <typename FormatContext, typename Arg, typename... Args> -- typename FormatContext::iterator format_args( -- const tuple_arg_join<Char, T...>& value, FormatContext& ctx, -- const Arg& arg, const Args&... args) { -+ auto format_args(const tuple_join_view<Char, T...>& value, FormatContext& ctx, -+ const Arg& arg, const Args&... args) -> -+ typename FormatContext::iterator { - using base = formatter<typename std::decay<Arg>::type, Char>; -- auto out = ctx.out(); -- out = base{}.format(arg, ctx); -+ auto out = base().format(arg, ctx); - if (sizeof...(Args) > 0) { - out = std::copy(value.sep.begin(), value.sep.end(), out); - ctx.advance_to(out); -@@ -345,6 +418,8 @@ struct formatter<tuple_arg_join<Char, T...>, Char> { - } - }; - -+FMT_MODULE_EXPORT_BEGIN -+ - /** - \rst - Returns an object that formats `tuple` with elements separated by `sep`. -@@ -357,14 +432,15 @@ struct formatter<tuple_arg_join<Char, T...>, Char> { - \endrst - */ - template <typename... T> --FMT_CONSTEXPR tuple_arg_join<char, T...> join(const std::tuple<T...>& tuple, -- string_view sep) { -+FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep) -+ -> tuple_join_view<char, T...> { - return {tuple, sep}; - } - - template <typename... T> --FMT_CONSTEXPR tuple_arg_join<wchar_t, T...> join(const std::tuple<T...>& tuple, -- wstring_view sep) { -+FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, -+ basic_string_view<wchar_t> sep) -+ -> tuple_join_view<wchar_t, T...> { - return {tuple, sep}; - } - -@@ -380,17 +456,12 @@ FMT_CONSTEXPR tuple_arg_join<wchar_t, T...> join(const std::tuple<T...>& tuple, - \endrst - */ - template <typename T> --arg_join<const T*, const T*, char> join(std::initializer_list<T> list, -- string_view sep) { -- return join(std::begin(list), std::end(list), sep); --} -- --template <typename T> --arg_join<const T*, const T*, wchar_t> join(std::initializer_list<T> list, -- wstring_view sep) { -+auto join(std::initializer_list<T> list, string_view sep) -+ -> join_view<const T*, const T*> { - return join(std::begin(list), std::end(list), sep); - } - -+FMT_MODULE_EXPORT_END - FMT_END_NAMESPACE - - #endif // FMT_RANGES_H_ -diff --git a/src/fmt.cpp b/src/fmt.cpp -index 9e91beb1..edd52dd5 100644 ---- a/src/fmt.cpp -+++ b/src/fmt.cpp -@@ -10,94 +10,58 @@ - #include <spdlog/fmt/bundled/format-inl.h> - - -+ - FMT_BEGIN_NAMESPACE - namespace detail { - --template <typename T> --int format_float(char* buf, std::size_t size, const char* format, int precision, -- T value) { --#ifdef FMT_FUZZ -- if (precision > 100000) -- throw std::runtime_error( -- "fuzz mode - avoid large allocation inside snprintf"); --#endif -- // Suppress the warning about nonliteral format string. -- int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF; -- return precision < 0 ? snprintf_ptr(buf, size, format, value) -- : snprintf_ptr(buf, size, format, precision, value); -+template<typename T> -+int format_float(char *buf, std::size_t size, const char *format, int precision, T value) -+{ -+# ifdef FMT_FUZZ -+ if (precision > 100000) -+ throw std::runtime_error("fuzz mode - avoid large allocation inside snprintf"); -+# endif -+ // Suppress the warning about nonliteral format string. -+ int (*snprintf_ptr)(char *, size_t, const char *, ...) = FMT_SNPRINTF; -+ return precision < 0 ? snprintf_ptr(buf, size, format, value) : snprintf_ptr(buf, size, format, precision, value); - } - --template FMT_API dragonbox::decimal_fp<float> dragonbox::to_decimal(float x) -- FMT_NOEXCEPT; --template FMT_API dragonbox::decimal_fp<double> dragonbox::to_decimal(double x) -- FMT_NOEXCEPT; -- --// DEPRECATED! This function exists for ABI compatibility. --template <typename Char> --typename basic_format_context<std::back_insert_iterator<buffer<Char>>, -- Char>::iterator --vformat_to(buffer<Char>& buf, basic_string_view<Char> format_str, -- basic_format_args<basic_format_context< -- std::back_insert_iterator<buffer<type_identity_t<Char>>>, -- type_identity_t<Char>>> -- args) { -- using iterator = std::back_insert_iterator<buffer<char>>; -- using context = basic_format_context< -- std::back_insert_iterator<buffer<type_identity_t<Char>>>, -- type_identity_t<Char>>; -- auto out = iterator(buf); -- format_handler<iterator, Char, context> h(out, format_str, args, {}); -- parse_format_string<false>(format_str, h); -- return out; --} --template basic_format_context<std::back_insert_iterator<buffer<char>>, -- char>::iterator --vformat_to(buffer<char>&, string_view, -- basic_format_args<basic_format_context< -- std::back_insert_iterator<buffer<type_identity_t<char>>>, -- type_identity_t<char>>>); --} // namespace detail -- --template struct FMT_INSTANTIATION_DEF_API detail::basic_data<void>; -+template FMT_API dragonbox::decimal_fp<float> dragonbox::to_decimal(float x) FMT_NOEXCEPT; -+template FMT_API dragonbox::decimal_fp<double> dragonbox::to_decimal(double x) FMT_NOEXCEPT; -+} // namespace detail - - // Workaround a bug in MSVC2013 that prevents instantiation of format_float. --int (*instantiate_format_float)(double, int, detail::float_specs, -- detail::buffer<char>&) = detail::format_float; -+int (*instantiate_format_float)(double, int, detail::float_specs, detail::buffer<char> &) = detail::format_float; - --#ifndef FMT_STATIC_THOUSANDS_SEPARATOR --template FMT_API detail::locale_ref::locale_ref(const std::locale& loc); -+# ifndef FMT_STATIC_THOUSANDS_SEPARATOR -+template FMT_API detail::locale_ref::locale_ref(const std::locale &loc); - template FMT_API std::locale detail::locale_ref::get<std::locale>() const; --#endif -+# endif - - // Explicit instantiations for char. - --template FMT_API std::string detail::grouping_impl<char>(locale_ref); --template FMT_API char detail::thousands_sep_impl(locale_ref); -+template FMT_API auto detail::thousands_sep_impl(locale_ref) -> thousands_sep_result<char>; - template FMT_API char detail::decimal_point_impl(locale_ref); - --template FMT_API void detail::buffer<char>::append(const char*, const char*); -+template FMT_API void detail::buffer<char>::append(const char *, const char *); - - template FMT_API void detail::vformat_to( -- detail::buffer<char>&, string_view, -- basic_format_args<FMT_BUFFER_CONTEXT(char)>, detail::locale_ref); -- --template FMT_API int detail::snprintf_float(double, int, detail::float_specs, -- detail::buffer<char>&); --template FMT_API int detail::snprintf_float(long double, int, -- detail::float_specs, -- detail::buffer<char>&); --template FMT_API int detail::format_float(double, int, detail::float_specs, -- detail::buffer<char>&); --template FMT_API int detail::format_float(long double, int, detail::float_specs, -- detail::buffer<char>&); -+ detail::buffer<char> &, string_view, basic_format_args<FMT_BUFFER_CONTEXT(char)>, detail::locale_ref); -+ -+template FMT_API int detail::snprintf_float(double, int, detail::float_specs, detail::buffer<char> &); -+template FMT_API int detail::snprintf_float(long double, int, detail::float_specs, detail::buffer<char> &); -+template FMT_API int detail::format_float(double, int, detail::float_specs, detail::buffer<char> &); -+template FMT_API int detail::format_float(long double, int, detail::float_specs, detail::buffer<char> &); - - // Explicit instantiations for wchar_t. - --template FMT_API std::string detail::grouping_impl<wchar_t>(locale_ref); --template FMT_API wchar_t detail::thousands_sep_impl(locale_ref); -+template FMT_API auto detail::thousands_sep_impl(locale_ref) -> thousands_sep_result<wchar_t>; - template FMT_API wchar_t detail::decimal_point_impl(locale_ref); - --template FMT_API void detail::buffer<wchar_t>::append(const wchar_t*, -- const wchar_t*); -+template FMT_API void detail::buffer<wchar_t>::append(const wchar_t *, const wchar_t *); -+ -+template struct detail::basic_data<void>; -+ - FMT_END_NAMESPACE -+ - #endif // !SPDLOG_FMT_EXTERNAL --- -2.32.0 - diff --git a/community/spdlog/APKBUILD b/community/spdlog/APKBUILD index 263541c9d39..04281e1d982 100644 --- a/community/spdlog/APKBUILD +++ b/community/spdlog/APKBUILD @@ -1,17 +1,15 @@ # Contributor: Leo <thinkabit.ukim@gmail.com> # Maintainer: Bart Ribbers <bribbers@disroot.org> pkgname=spdlog -pkgver=1.8.5 -pkgrel=1 +pkgver=1.9.2 +pkgrel=0 pkgdesc="Fast C++ logging library" url="https://github.com/gabime/spdlog" arch="all" license="MIT" makedepends="cmake fmt-dev" subpackages="$pkgname-dev" -source="https://github.com/gabime/spdlog/archive/v$pkgver/spdlog-v$pkgver.tar.gz - 0001-Update-fmt-version-8.0.patch - " +source="https://github.com/gabime/spdlog/archive/v$pkgver/spdlog-v$pkgver.tar.gz" build() { cmake -B build \ @@ -38,6 +36,5 @@ package() { } sha512sums=" -77cc9df0c40bbdbfe1f3e5818dccf121918bfceac28f2608f39e5bf944968b7e8e24a6fc29f01bc58a9bae41b8892d49cfb59c196935ec9868884320b50f130c spdlog-v1.8.5.tar.gz -df07d04c0b768559ccf994c6a809576335fe1fa862e4f629737b83ed6c58ab05c0d696cf455d544f6275fa0e7869db809d5c59119be97b9e95ce42cc2378c3cd 0001-Update-fmt-version-8.0.patch +87b12a792cf2d740ef29db4b6055788a487b6d474662b878711b8a5534efea5f0d97b6ac357834500b66cc65e1ba8934446a695e9691fd5d4b95397b6871555c spdlog-v1.9.2.tar.gz " |