diff options
| author | 2025-04-13 17:03:08 +0100 | |
|---|---|---|
| committer | 2025-04-13 17:03:08 +0100 | |
| commit | d0e321b92c55902ccb3ca98ddd8553cb57e55c77 (patch) | |
| tree | d7e0f9cdbe7d292b8409b0156da449eb9299c74e | |
| parent | Merge branch 'insp4' into master. (diff) | |
| parent | Remove the {fmt} headers that we don't use. (diff) | |
Merge branch 'insp4' into master.
| -rw-r--r-- | make/directive.pm | 18 | ||||
| -rw-r--r-- | modules/httpd.cpp | 9 | ||||
| -rw-r--r-- | modules/spanningtree/utils.cpp | 6 | ||||
| -rw-r--r-- | modules/websocket.cpp | 11 | ||||
| -rw-r--r-- | vendor/fmt/LICENSE (renamed from vendor/fmt/LICENSE.rst) | 0 | ||||
| -rw-r--r-- | vendor/fmt/args.h | 220 | ||||
| -rw-r--r-- | vendor/fmt/chrono.h | 2338 | ||||
| -rw-r--r-- | vendor/fmt/os.h | 427 | ||||
| -rw-r--r-- | vendor/fmt/ostream.h | 166 | ||||
| -rw-r--r-- | vendor/fmt/printf.h | 633 | ||||
| -rw-r--r-- | vendor/fmt/ranges.h | 850 | ||||
| -rw-r--r-- | vendor/fmt/std.h | 726 | ||||
| -rw-r--r-- | vendor/fmt/xchar.h | 373 | ||||
| -rw-r--r-- | vendor/update.toml | 2 |
14 files changed, 41 insertions, 5738 deletions
diff --git a/make/directive.pm b/make/directive.pm index 14d587572..aa3005750 100644 --- a/make/directive.pm +++ b/make/directive.pm @@ -345,6 +345,24 @@ sub __function_require_library { return $ok; } +sub __function_require_environment { + my ($file, $name, $value) = @_; + + # Check for an inverted match. + my ($ok, $err) = ("", undef); + if ($name =~ s/^!//) { + ($ok, $err) = ($err, $ok); + } + + return $err unless defined $ENV{$name}; + if (defined $value) { + return $err unless $ENV{$name} eq $value; + } + + # Requirement directives don't change anything directly. + return $ok; +} + sub __function_warning { my ($file, @messages) = @_; print_warning @messages; diff --git a/modules/httpd.cpp b/modules/httpd.cpp index af9ef5f26..42fea8152 100644 --- a/modules/httpd.cpp +++ b/modules/httpd.cpp @@ -26,6 +26,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/// $CompilerFlags: require_environment("SYSTEM_HTTP_PARSER" "1") -DUSE_SYSTEM_HTTP_PARSER +/// $LinkerFlags: require_environment("SYSTEM_HTTP_PARSER" "1") -lhttp_parser + #include "inspircd.h" #include "iohook.h" @@ -41,7 +44,11 @@ # pragma GCC diagnostic ignored "-Wshadow" #endif -#include <http_parser/http_parser.c> +#ifdef USE_SYSTEM_HTTP_PARSER +# include <http_parser.h> +#else +# include <http_parser/http_parser.c> +#endif #ifdef __GNUC__ # pragma GCC diagnostic pop diff --git a/modules/spanningtree/utils.cpp b/modules/spanningtree/utils.cpp index 9477f9d72..66d5d3444 100644 --- a/modules/spanningtree/utils.cpp +++ b/modules/spanningtree/utils.cpp @@ -296,6 +296,12 @@ void SpanningTreeUtilities::ReadConfiguration() L->Bind = tag->getString("bind"); L->Hidden = tag->getBool("hidden"); + if (!tag->getString("ssl").empty()) + { + throw ModuleException((Module*)Creator, "Obsolete TLS configuration in link block at {}. See {}modules/spanningtree/#link for the correct way to configure TLS.", + tag->source.str(), INSPIRCD_DOCS); + } + if (L->Name.empty()) throw ModuleException((Module*)Creator, "Invalid configuration, found a link tag without a name!" + (!L->IPAddr.empty() ? " IP address: "+L->IPAddr : "")); diff --git a/modules/websocket.cpp b/modules/websocket.cpp index 4212b9611..fdf91fbe0 100644 --- a/modules/websocket.cpp +++ b/modules/websocket.cpp @@ -19,6 +19,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/// $CompilerFlags: require_environment("SYSTEM_UTFCPP" "1") -DUSE_SYSTEM_UTFCPP + + +#ifdef USE_SYSTEM_UTFCPP +# include <utf8cpp/utf8/unchecked.h> +#else +# include <utfcpp/unchecked.h> +#endif #include "inspircd.h" #include "extension.h" @@ -28,9 +36,6 @@ #include "modules/whois.h" #include "utility/string.h" -#define UTF_CPP_CPLUSPLUS 199711L -#include <utfcpp/unchecked.h> - static constexpr char MagicGUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; static constexpr char newline[] = "\r\n"; static constexpr char whitespace[] = " \t"; diff --git a/vendor/fmt/LICENSE.rst b/vendor/fmt/LICENSE index 1cd1ef926..1cd1ef926 100644 --- a/vendor/fmt/LICENSE.rst +++ b/vendor/fmt/LICENSE diff --git a/vendor/fmt/args.h b/vendor/fmt/args.h deleted file mode 100644 index 3ff478807..000000000 --- a/vendor/fmt/args.h +++ /dev/null @@ -1,220 +0,0 @@ -// Formatting library for C++ - dynamic argument lists -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_ARGS_H_ -#define FMT_ARGS_H_ - -#ifndef FMT_MODULE -# include <functional> // std::reference_wrapper -# include <memory> // std::unique_ptr -# include <vector> -#endif - -#include "format.h" // std_string_view - -FMT_BEGIN_NAMESPACE -namespace detail { - -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> auto unwrap(const T& v) -> const T& { return v; } -template <typename T> -auto unwrap(const std::reference_wrapper<T>& v) -> const T& { - return static_cast<const T&>(v); -} - -// node is defined outside dynamic_arg_list to workaround a C2504 bug in MSVC -// 2022 (v17.10.0). -// -// 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 node is made a fake template. -template <typename = void> struct node { - virtual ~node() = default; - std::unique_ptr<node<>> next; -}; - -class dynamic_arg_list { - 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> auto push(const Arg& arg) -> const T& { - 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 - -/** - * A dynamic list of formatting arguments with storage. - * - * It can be implicitly converted into `fmt::basic_format_args` for passing - * into type-erased formatting functions such as `fmt::vformat`. - */ -template <typename Context> class dynamic_format_arg_store { - private: - using char_type = typename Context::char_type; - - template <typename T> struct need_copy { - static constexpr detail::type mapped_type = - detail::mapped_type_constant<T, char_type>::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)) - }; - }; - - template <typename T> - using stored_t = conditional_t< - std::is_convertible<T, std::basic_string<char_type>>::value && - !detail::is_reference_wrapper<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>; - - auto data() const -> const basic_format_arg<Context>* { - return named_info_.empty() ? data_.data() : data_.data() + 1; - } - - template <typename T> void emplace_arg(const T& arg) { - data_.emplace_back(arg); - } - - template <typename T> - void emplace_arg(const detail::named_arg<char_type, T>& arg) { - if (named_info_.empty()) - data_.insert(data_.begin(), basic_format_arg<Context>(nullptr, 0)); - data_.emplace_back(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] = {named_info_.data(), named_info_.size()}; - guard.release(); - } - - public: - constexpr dynamic_format_arg_store() = default; - - operator basic_format_args<Context>() const { - return basic_format_args<Context>(data(), static_cast<int>(data_.size()), - !named_info_.empty()); - } - - /** - * 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); - */ - template <typename T> void push_back(const T& arg) { - if (detail::const_check(need_copy<T>::value)) - emplace_arg(dynamic_args_.push<stored_t<T>>(arg)); - else - emplace_arg(detail::unwrap(arg)); - } - - /** - * Adds a reference to the argument into the dynamic store for later passing - * to a formatting function. - * - * **Example**: - * - * fmt::dynamic_format_arg_store<fmt::format_context> store; - * char band[] = "Rolling Stones"; - * store.push_back(std::cref(band)); - * band[9] = 'c'; // Changing str affects the output. - * std::string result = fmt::vformat("{}", store); - * // result == "Rolling Scones" - */ - template <typename T> void push_back(std::reference_wrapper<T> arg) { - static_assert( - 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. The name is always copied into the store. - */ - 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_t<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_ = {}; - } - - /// Reserves space to store at least `new_cap` arguments including - /// `new_cap_named` named arguments. - 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); - } - - /// Returns the number of elements in the store. - size_t size() const noexcept { return data_.size(); } -}; - -FMT_END_NAMESPACE - -#endif // FMT_ARGS_H_ diff --git a/vendor/fmt/chrono.h b/vendor/fmt/chrono.h deleted file mode 100644 index 50c777c84..000000000 --- a/vendor/fmt/chrono.h +++ /dev/null @@ -1,2338 +0,0 @@ -// Formatting library for C++ - chrono support -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_CHRONO_H_ -#define FMT_CHRONO_H_ - -#ifndef FMT_MODULE -# include <algorithm> -# include <chrono> -# include <cmath> // std::isfinite -# include <cstring> // std::memcpy -# include <ctime> -# include <iterator> -# include <locale> -# include <ostream> -# include <type_traits> -#endif - -#include "format.h" - -namespace fmt_detail { -struct time_zone { - template <typename Duration, typename T> - auto to_sys(T) - -> std::chrono::time_point<std::chrono::system_clock, Duration> { - return {}; - } -}; -template <typename... T> inline auto current_zone(T...) -> time_zone* { - return nullptr; -} - -template <typename... T> inline void _tzset(T...) {} -} // namespace fmt_detail - -FMT_BEGIN_NAMESPACE - -// Enable safe chrono durations, unless explicitly disabled. -#ifndef FMT_SAFE_DURATION_CAST -# define FMT_SAFE_DURATION_CAST 1 -#endif -#if FMT_SAFE_DURATION_CAST - -// For conversion between std::chrono::durations without undefined -// behaviour or erroneous results. -// This is a stripped down version of duration_cast, for inclusion in fmt. -// See https://github.com/pauldreik/safe_duration_cast -// -// Copyright Paul Dreik 2019 -namespace safe_duration_cast { - -template <typename To, typename From, - FMT_ENABLE_IF(!std::is_same<From, To>::value && - std::numeric_limits<From>::is_signed == - std::numeric_limits<To>::is_signed)> -FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) - -> To { - ec = 0; - using F = std::numeric_limits<From>; - using T = std::numeric_limits<To>; - static_assert(F::is_integer, "From must be integral"); - static_assert(T::is_integer, "To must be integral"); - - // A and B are both signed, or both unsigned. - if (detail::const_check(F::digits <= T::digits)) { - // From fits in To without any problem. - } else { - // From does not always fit in To, resort to a dynamic check. - if (from < (T::min)() || from > (T::max)()) { - // outside range. - ec = 1; - return {}; - } - } - return static_cast<To>(from); -} - -/// Converts From to To, without loss. If the dynamic value of from -/// can't be converted to To without loss, ec is set. -template <typename To, typename From, - FMT_ENABLE_IF(!std::is_same<From, To>::value && - std::numeric_limits<From>::is_signed != - std::numeric_limits<To>::is_signed)> -FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) - -> To { - ec = 0; - using F = std::numeric_limits<From>; - using T = std::numeric_limits<To>; - static_assert(F::is_integer, "From must be integral"); - static_assert(T::is_integer, "To must be integral"); - - if (detail::const_check(F::is_signed && !T::is_signed)) { - // From may be negative, not allowed! - if (fmt::detail::is_negative(from)) { - ec = 1; - return {}; - } - // From is positive. Can it always fit in To? - if (detail::const_check(F::digits > T::digits) && - from > static_cast<From>(detail::max_value<To>())) { - ec = 1; - return {}; - } - } - - if (detail::const_check(!F::is_signed && T::is_signed && - F::digits >= T::digits) && - from > static_cast<From>(detail::max_value<To>())) { - ec = 1; - return {}; - } - return static_cast<To>(from); // Lossless conversion. -} - -template <typename To, typename From, - FMT_ENABLE_IF(std::is_same<From, To>::value)> -FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) - -> To { - ec = 0; - return from; -} // function - -// clang-format off -/** - * converts From to To if possible, otherwise ec is set. - * - * input | output - * ---------------------------------|--------------- - * NaN | NaN - * Inf | Inf - * normal, fits in output | converted (possibly lossy) - * normal, does not fit in output | ec is set - * subnormal | best effort - * -Inf | -Inf - */ -// clang-format on -template <typename To, typename From, - FMT_ENABLE_IF(!std::is_same<From, To>::value)> -FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To { - ec = 0; - using T = std::numeric_limits<To>; - static_assert(std::is_floating_point<From>::value, "From must be floating"); - static_assert(std::is_floating_point<To>::value, "To must be floating"); - - // catch the only happy case - if (std::isfinite(from)) { - if (from >= T::lowest() && from <= (T::max)()) { - return static_cast<To>(from); - } - // not within range. - ec = 1; - return {}; - } - - // nan and inf will be preserved - return static_cast<To>(from); -} // function - -template <typename To, typename From, - FMT_ENABLE_IF(std::is_same<From, To>::value)> -FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To { - ec = 0; - static_assert(std::is_floating_point<From>::value, "From must be floating"); - return from; -} - -/// Safe duration_cast between floating point durations -template <typename To, typename FromRep, typename FromPeriod, - FMT_ENABLE_IF(std::is_floating_point<FromRep>::value), - FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)> -auto safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from, - int& ec) -> To { - using From = std::chrono::duration<FromRep, FromPeriod>; - ec = 0; - if (std::isnan(from.count())) { - // nan in, gives nan out. easy. - return To{std::numeric_limits<typename To::rep>::quiet_NaN()}; - } - // maybe we should also check if from is denormal, and decide what to do about - // it. - - // +-inf should be preserved. - if (std::isinf(from.count())) { - return To{from.count()}; - } - - // the basic idea is that we need to convert from count() in the from type - // to count() in the To type, by multiplying it with this: - struct Factor - : std::ratio_divide<typename From::period, typename To::period> {}; - - static_assert(Factor::num > 0, "num must be positive"); - static_assert(Factor::den > 0, "den must be positive"); - - // the conversion is like this: multiply from.count() with Factor::num - // /Factor::den and convert it to To::rep, all this without - // overflow/underflow. let's start by finding a suitable type that can hold - // both To, From and Factor::num - using IntermediateRep = - typename std::common_type<typename From::rep, typename To::rep, - decltype(Factor::num)>::type; - - // force conversion of From::rep -> IntermediateRep to be safe, - // even if it will never happen be narrowing in this context. - IntermediateRep count = - safe_float_conversion<IntermediateRep>(from.count(), ec); - if (ec) { - return {}; - } - - // multiply with Factor::num without overflow or underflow - if (detail::const_check(Factor::num != 1)) { - constexpr auto max1 = detail::max_value<IntermediateRep>() / - static_cast<IntermediateRep>(Factor::num); - if (count > max1) { - ec = 1; - return {}; - } - constexpr auto min1 = std::numeric_limits<IntermediateRep>::lowest() / - static_cast<IntermediateRep>(Factor::num); - if (count < min1) { - ec = 1; - return {}; - } - count *= static_cast<IntermediateRep>(Factor::num); - } - - // this can't go wrong, right? den>0 is checked earlier. - if (detail::const_check(Factor::den != 1)) { - using common_t = typename std::common_type<IntermediateRep, intmax_t>::type; - count /= static_cast<common_t>(Factor::den); - } - - // convert to the to type, safely - using ToRep = typename To::rep; - - const ToRep tocount = safe_float_conversion<ToRep>(count, ec); - if (ec) { - return {}; - } - return To{tocount}; -} -} // namespace safe_duration_cast -#endif - -namespace detail { - -// Check if std::chrono::utc_time is available. -#ifdef FMT_USE_UTC_TIME -// Use the provided definition. -#elif defined(__cpp_lib_chrono) -# define FMT_USE_UTC_TIME (__cpp_lib_chrono >= 201907L) -#else -# define FMT_USE_UTC_TIME 0 -#endif -#if FMT_USE_UTC_TIME -using utc_clock = std::chrono::utc_clock; -#else -struct utc_clock { - template <typename T> void to_sys(T); -}; -#endif - -// Check if std::chrono::local_time is available. -#ifdef FMT_USE_LOCAL_TIME -// Use the provided definition. -#elif defined(__cpp_lib_chrono) -# define FMT_USE_LOCAL_TIME (__cpp_lib_chrono >= 201907L) -#else -# define FMT_USE_LOCAL_TIME 0 -#endif -#if FMT_USE_LOCAL_TIME -using local_t = std::chrono::local_t; -#else -struct local_t {}; -#endif - -} // namespace detail - -template <typename Duration> -using sys_time = std::chrono::time_point<std::chrono::system_clock, Duration>; - -template <typename Duration> -using utc_time = std::chrono::time_point<detail::utc_clock, Duration>; - -template <class Duration> -using local_time = std::chrono::time_point<detail::local_t, Duration>; - -namespace detail { - -// Prevents expansion of a preceding token as a function-style macro. -// Usage: f FMT_NOMACRO() -#define FMT_NOMACRO - -template <typename T = void> struct null {}; -inline auto localtime_r FMT_NOMACRO(...) -> null<> { return null<>(); } -inline auto localtime_s(...) -> null<> { return null<>(); } -inline auto gmtime_r(...) -> null<> { return null<>(); } -inline auto gmtime_s(...) -> null<> { return null<>(); } - -// It is defined here and not in ostream.h because the latter has expensive -// includes. -template <typename StreamBuf> class formatbuf : public StreamBuf { - private: - using char_type = typename StreamBuf::char_type; - using streamsize = decltype(std::declval<StreamBuf>().sputn(nullptr, 0)); - using int_type = typename StreamBuf::int_type; - using traits_type = typename StreamBuf::traits_type; - - buffer<char_type>& buffer_; - - public: - explicit formatbuf(buffer<char_type>& buf) : buffer_(buf) {} - - protected: - // The put area is always empty. This makes the implementation simpler and has - // the advantage that the streambuf and the buffer are always in sync and - // sputc never writes into uninitialized memory. A disadvantage is that each - // call to sputc always results in a (virtual) call to overflow. There is no - // disadvantage here for sputn since this always results in a call to xsputn. - - auto overflow(int_type ch) -> int_type override { - if (!traits_type::eq_int_type(ch, traits_type::eof())) - buffer_.push_back(static_cast<char_type>(ch)); - return ch; - } - - auto xsputn(const char_type* s, streamsize count) -> streamsize override { - buffer_.append(s, s + count); - return count; - } -}; - -inline auto get_classic_locale() -> const std::locale& { - static const auto& locale = std::locale::classic(); - return locale; -} - -template <typename CodeUnit> struct codecvt_result { - static constexpr const size_t max_size = 32; - CodeUnit buf[max_size]; - CodeUnit* end; -}; - -template <typename CodeUnit> -void write_codecvt(codecvt_result<CodeUnit>& out, string_view in, - const std::locale& loc) { - FMT_PRAGMA_CLANG(diagnostic push) - FMT_PRAGMA_CLANG(diagnostic ignored "-Wdeprecated") - auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc); - FMT_PRAGMA_CLANG(diagnostic pop) - auto mb = std::mbstate_t(); - const char* from_next = nullptr; - auto result = f.in(mb, in.begin(), in.end(), from_next, std::begin(out.buf), - std::end(out.buf), out.end); - if (result != std::codecvt_base::ok) - FMT_THROW(format_error("failed to format time")); -} - -template <typename OutputIt> -auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc) - -> OutputIt { - if (const_check(detail::use_utf8) && loc != get_classic_locale()) { - // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and - // gcc-4. -#if FMT_MSC_VERSION != 0 || \ - (defined(__GLIBCXX__) && \ - (!defined(_GLIBCXX_USE_DUAL_ABI) || _GLIBCXX_USE_DUAL_ABI == 0)) - // 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 - - using unit_t = codecvt_result<code_unit>; - unit_t unit; - write_codecvt(unit, in, loc); - // In UTF-8 is used one to four one-byte code units. - auto u = - to_utf8<code_unit, basic_memory_buffer<char, unit_t::max_size * 4>>(); - if (!u.convert({unit.buf, to_unsigned(unit.end - unit.buf)})) - FMT_THROW(format_error("failed to format time")); - return copy<char>(u.c_str(), u.c_str() + u.size(), out); - } - return copy<char>(in.data(), in.data() + in.size(), out); -} - -template <typename Char, typename OutputIt, - FMT_ENABLE_IF(!std::is_same<Char, char>::value)> -auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) - -> OutputIt { - codecvt_result<Char> unit; - write_codecvt(unit, sv, loc); - return copy<Char>(unit.buf, unit.end, out); -} - -template <typename Char, typename OutputIt, - FMT_ENABLE_IF(std::is_same<Char, char>::value)> -auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) - -> OutputIt { - return write_encoded_tm_str(out, sv, loc); -} - -template <typename Char> -inline void do_write(buffer<Char>& buf, const std::tm& time, - const std::locale& loc, char format, char modifier) { - auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf); - auto&& os = std::basic_ostream<Char>(&format_buf); - os.imbue(loc); - const auto& facet = std::use_facet<std::time_put<Char>>(loc); - auto end = facet.put(os, os, Char(' '), &time, format, modifier); - if (end.failed()) FMT_THROW(format_error("failed to format time")); -} - -template <typename Char, typename OutputIt, - FMT_ENABLE_IF(!std::is_same<Char, char>::value)> -auto write(OutputIt out, const std::tm& time, const std::locale& loc, - char format, char modifier = 0) -> OutputIt { - auto&& buf = get_buffer<Char>(out); - do_write<Char>(buf, time, loc, format, modifier); - return get_iterator(buf, out); -} - -template <typename Char, typename OutputIt, - FMT_ENABLE_IF(std::is_same<Char, char>::value)> -auto write(OutputIt out, const std::tm& time, const std::locale& loc, - char format, char modifier = 0) -> OutputIt { - auto&& buf = basic_memory_buffer<Char>(); - do_write<char>(buf, time, loc, format, modifier); - return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc); -} - -template <typename Rep1, typename Rep2> -struct is_same_arithmetic_type - : public std::integral_constant<bool, - (std::is_integral<Rep1>::value && - std::is_integral<Rep2>::value) || - (std::is_floating_point<Rep1>::value && - std::is_floating_point<Rep2>::value)> { -}; - -FMT_NORETURN inline void throw_duration_error() { - FMT_THROW(format_error("cannot format duration")); -} - -// Cast one integral duration to another with an overflow check. -template <typename To, typename FromRep, typename FromPeriod, - FMT_ENABLE_IF(std::is_integral<FromRep>::value&& - std::is_integral<typename To::rep>::value)> -auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To { -#if !FMT_SAFE_DURATION_CAST - return std::chrono::duration_cast<To>(from); -#else - // The conversion factor: to.count() == factor * from.count(). - using factor = std::ratio_divide<FromPeriod, typename To::period>; - - using common_rep = typename std::common_type<FromRep, typename To::rep, - decltype(factor::num)>::type; - - int ec = 0; - auto count = safe_duration_cast::lossless_integral_conversion<common_rep>( - from.count(), ec); - if (ec) throw_duration_error(); - - // Multiply from.count() by factor and check for overflow. - if (const_check(factor::num != 1)) { - if (count > max_value<common_rep>() / factor::num) throw_duration_error(); - const auto min = (std::numeric_limits<common_rep>::min)() / factor::num; - if (const_check(!std::is_unsigned<common_rep>::value) && count < min) - throw_duration_error(); - count *= factor::num; - } - if (const_check(factor::den != 1)) count /= factor::den; - auto to = - To(safe_duration_cast::lossless_integral_conversion<typename To::rep>( - count, ec)); - if (ec) throw_duration_error(); - return to; -#endif -} - -template <typename To, typename FromRep, typename FromPeriod, - FMT_ENABLE_IF(std::is_floating_point<FromRep>::value&& - std::is_floating_point<typename To::rep>::value)> -auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To { -#if FMT_SAFE_DURATION_CAST - // Throwing version of safe_duration_cast is only available for - // integer to integer or float to float casts. - int ec; - To to = safe_duration_cast::safe_duration_cast<To>(from, ec); - if (ec) throw_duration_error(); - return to; -#else - // Standard duration cast, may overflow. - return std::chrono::duration_cast<To>(from); -#endif -} - -template < - typename To, typename FromRep, typename FromPeriod, - FMT_ENABLE_IF(!is_same_arithmetic_type<FromRep, typename To::rep>::value)> -auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To { - // Mixed integer <-> float cast is not supported by safe_duration_cast. - return std::chrono::duration_cast<To>(from); -} - -template <typename Duration> -auto to_time_t(sys_time<Duration> time_point) -> std::time_t { - // Cannot use std::chrono::system_clock::to_time_t since this would first - // require a cast to std::chrono::system_clock::time_point, which could - // overflow. - return detail::duration_cast<std::chrono::duration<std::time_t>>( - time_point.time_since_epoch()) - .count(); -} - -// Workaround a bug in libstdc++ which sets __cpp_lib_chrono to 201907 without -// providing current_zone(): https://github.com/fmtlib/fmt/issues/4160. -template <typename T> FMT_CONSTEXPR auto has_current_zone() -> bool { - using namespace std::chrono; - using namespace fmt_detail; - return !std::is_same<decltype(current_zone()), fmt_detail::time_zone*>::value; -} -} // namespace detail - -FMT_BEGIN_EXPORT - -/** - * 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 auto localtime(std::time_t time) -> std::tm { - struct dispatcher { - std::time_t time_; - std::tm tm_; - - inline dispatcher(std::time_t t) : time_(t) {} - - inline auto run() -> bool { - using namespace fmt::detail; - return handle(localtime_r(&time_, &tm_)); - } - - inline auto handle(std::tm* tm) -> bool { return tm != nullptr; } - - inline auto handle(detail::null<>) -> bool { - using namespace fmt::detail; - return fallback(localtime_s(&tm_, &time_)); - } - - inline auto fallback(int res) -> bool { return res == 0; } - -#if !FMT_MSC_VERSION - inline auto fallback(detail::null<>) -> bool { - using namespace fmt::detail; - std::tm* tm = std::localtime(&time_); - if (tm) tm_ = *tm; - return tm != nullptr; - } -#endif - }; - dispatcher lt(time); - // Too big time values may be unsupported. - if (!lt.run()) FMT_THROW(format_error("time_t value out of range")); - return lt.tm_; -} - -#if FMT_USE_LOCAL_TIME -template <typename Duration, - FMT_ENABLE_IF(detail::has_current_zone<Duration>())> -inline auto localtime(std::chrono::local_time<Duration> time) -> std::tm { - using namespace std::chrono; - using namespace fmt_detail; - return localtime(detail::to_time_t(current_zone()->to_sys<Duration>(time))); -} -#endif - -/** - * 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 auto gmtime(std::time_t time) -> std::tm { - struct dispatcher { - std::time_t time_; - std::tm tm_; - - inline dispatcher(std::time_t t) : time_(t) {} - - inline auto run() -> bool { - using namespace fmt::detail; - return handle(gmtime_r(&time_, &tm_)); - } - - inline auto handle(std::tm* tm) -> bool { return tm != nullptr; } - - inline auto handle(detail::null<>) -> bool { - using namespace fmt::detail; - return fallback(gmtime_s(&tm_, &time_)); - } - - inline auto fallback(int res) -> bool { return res == 0; } - -#if !FMT_MSC_VERSION - inline auto fallback(detail::null<>) -> bool { - std::tm* tm = std::gmtime(&time_); - if (tm) tm_ = *tm; - return tm != nullptr; - } -#endif - }; - auto gt = dispatcher(time); - // Too big time values may be unsupported. - if (!gt.run()) FMT_THROW(format_error("time_t value out of range")); - return gt.tm_; -} - -template <typename Duration> -inline auto gmtime(sys_time<Duration> time_point) -> std::tm { - return gmtime(detail::to_time_t(time_point)); -} - -namespace detail { - -// Writes two-digit numbers a, b and c separated by sep to buf. -// The method by Pavel Novikov based on -// https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/. -inline void write_digit2_separated(char* buf, unsigned a, unsigned b, - unsigned c, char sep) { - unsigned long long digits = - a | (b << 24) | (static_cast<unsigned long long>(c) << 48); - // Convert each value to BCD. - // We have x = a * 10 + b and we want to convert it to BCD y = a * 16 + b. - // The difference is - // y - x = a * 6 - // a can be found from x: - // a = floor(x / 10) - // then - // y = x + a * 6 = x + floor(x / 10) * 6 - // floor(x / 10) is (x * 205) >> 11 (needs 16 bits). - digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6; - // Put low nibbles to high bytes and high nibbles to low bytes. - digits = ((digits & 0x00f00000f00000f0) >> 4) | - ((digits & 0x000f00000f00000f) << 8); - auto usep = static_cast<unsigned long long>(sep); - // Add ASCII '0' to each digit byte and insert separators. - digits |= 0x3030003030003030 | (usep << 16) | (usep << 40); - - constexpr const size_t len = 8; - if (const_check(is_big_endian())) { - char tmp[len]; - std::memcpy(tmp, &digits, len); - std::reverse_copy(tmp, tmp + len, buf); - } else { - std::memcpy(buf, &digits, len); - } -} - -template <typename Period> -FMT_CONSTEXPR inline auto get_units() -> const char* { - 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 detail::use_utf8 ? "µs" : "us"; - 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 "min"; - if (std::is_same<Period, std::ratio<3600>>::value) return "h"; - if (std::is_same<Period, std::ratio<86400>>::value) return "d"; - return nullptr; -} - -enum class numeric_system { - standard, - // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale. - alternative -}; - -// Glibc extensions for formatting numeric values. -enum class pad_type { - // Pad a numeric result string with zeros (the default). - zero, - // Do not pad a numeric result string. - none, - // Pad a numeric result string with spaces. - space, -}; - -template <typename OutputIt> -auto write_padding(OutputIt out, pad_type pad, int width) -> OutputIt { - if (pad == pad_type::none) return out; - return detail::fill_n(out, width, pad == pad_type::space ? ' ' : '0'); -} - -template <typename OutputIt> -auto write_padding(OutputIt out, pad_type pad) -> OutputIt { - if (pad != pad_type::none) *out++ = pad == pad_type::space ? ' ' : '0'; - return out; -} - -// Parses a put_time-like format string and invokes handler actions. -template <typename Char, typename Handler> -FMT_CONSTEXPR auto parse_chrono_format(const Char* begin, const Char* end, - Handler&& handler) -> const Char* { - if (begin == end || *begin == '}') return begin; - if (*begin != '%') FMT_THROW(format_error("invalid format")); - auto ptr = begin; - while (ptr != end) { - pad_type pad = pad_type::zero; - auto c = *ptr; - if (c == '}') break; - if (c != '%') { - ++ptr; - continue; - } - if (begin != ptr) handler.on_text(begin, ptr); - ++ptr; // consume '%' - if (ptr == end) FMT_THROW(format_error("invalid format")); - c = *ptr; - switch (c) { - case '_': - pad = pad_type::space; - ++ptr; - break; - case '-': - pad = pad_type::none; - ++ptr; - break; - } - if (ptr == end) FMT_THROW(format_error("invalid format")); - c = *ptr++; - switch (c) { - case '%': handler.on_text(ptr - 1, ptr); break; - case 'n': { - const Char newline[] = {'\n'}; - handler.on_text(newline, newline + 1); - break; - } - case 't': { - const Char tab[] = {'\t'}; - handler.on_text(tab, tab + 1); - break; - } - // Year: - case 'Y': handler.on_year(numeric_system::standard, pad); break; - case 'y': handler.on_short_year(numeric_system::standard); break; - case 'C': handler.on_century(numeric_system::standard); break; - case 'G': handler.on_iso_week_based_year(); break; - case 'g': handler.on_iso_week_based_short_year(); break; - // Day of the week: - case 'a': handler.on_abbr_weekday(); break; - case 'A': handler.on_full_weekday(); break; - case 'w': handler.on_dec0_weekday(numeric_system::standard); break; - case 'u': handler.on_dec1_weekday(numeric_system::standard); break; - // Month: - case 'b': - case 'h': handler.on_abbr_month(); break; - case 'B': handler.on_full_month(); break; - case 'm': handler.on_dec_month(numeric_system::standard, pad); break; - // Day of the year/month: - case 'U': - handler.on_dec0_week_of_year(numeric_system::standard, pad); - break; - case 'W': - handler.on_dec1_week_of_year(numeric_system::standard, pad); - break; - case 'V': handler.on_iso_week_of_year(numeric_system::standard, pad); break; - case 'j': handler.on_day_of_year(pad); break; - case 'd': handler.on_day_of_month(numeric_system::standard, pad); break; - case 'e': - handler.on_day_of_month(numeric_system::standard, pad_type::space); - break; - // Hour, minute, second: - case 'H': handler.on_24_hour(numeric_system::standard, pad); break; - case 'I': handler.on_12_hour(numeric_system::standard, pad); break; - case 'M': handler.on_minute(numeric_system::standard, pad); break; - case 'S': handler.on_second(numeric_system::standard, pad); break; - // Other: - case 'c': handler.on_datetime(numeric_system::standard); break; - case 'x': handler.on_loc_date(numeric_system::standard); break; - case 'X': handler.on_loc_time(numeric_system::standard); break; - case 'D': handler.on_us_date(); break; - case 'F': handler.on_iso_date(); break; - case 'r': handler.on_12_hour_time(); break; - case 'R': handler.on_24_hour_time(); break; - case 'T': handler.on_iso_time(); break; - case 'p': handler.on_am_pm(); break; - case 'Q': handler.on_duration_value(); break; - case 'q': handler.on_duration_unit(); break; - case 'z': handler.on_utc_offset(numeric_system::standard); break; - case 'Z': handler.on_tz_name(); break; - // Alternative representation: - case 'E': { - if (ptr == end) FMT_THROW(format_error("invalid format")); - c = *ptr++; - switch (c) { - case 'Y': handler.on_year(numeric_system::alternative, pad); break; - case 'y': handler.on_offset_year(); break; - case 'C': handler.on_century(numeric_system::alternative); break; - case 'c': handler.on_datetime(numeric_system::alternative); break; - case 'x': handler.on_loc_date(numeric_system::alternative); break; - case 'X': handler.on_loc_time(numeric_system::alternative); break; - case 'z': handler.on_utc_offset(numeric_system::alternative); break; - default: FMT_THROW(format_error("invalid format")); - } - break; - } - case 'O': - if (ptr == end) FMT_THROW(format_error("invalid format")); - c = *ptr++; - switch (c) { - case 'y': handler.on_short_year(numeric_system::alternative); break; - case 'm': handler.on_dec_month(numeric_system::alternative, pad); break; - case 'U': - handler.on_dec0_week_of_year(numeric_system::alternative, pad); - break; - case 'W': - handler.on_dec1_week_of_year(numeric_system::alternative, pad); - break; - case 'V': - handler.on_iso_week_of_year(numeric_system::alternative, pad); - break; - case 'd': - handler.on_day_of_month(numeric_system::alternative, pad); - break; - case 'e': - handler.on_day_of_month(numeric_system::alternative, pad_type::space); - break; - case 'w': handler.on_dec0_weekday(numeric_system::alternative); break; - case 'u': handler.on_dec1_weekday(numeric_system::alternative); break; - case 'H': handler.on_24_hour(numeric_system::alternative, pad); break; - case 'I': handler.on_12_hour(numeric_system::alternative, pad); break; - case 'M': handler.on_minute(numeric_system::alternative, pad); break; - case 'S': handler.on_second(numeric_system::alternative, pad); break; - case 'z': handler.on_utc_offset(numeric_system::alternative); break; - default: FMT_THROW(format_error("invalid format")); - } - break; - default: FMT_THROW(format_error("invalid format")); - } - begin = ptr; - } - if (begin != ptr) handler.on_text(begin, ptr); - return ptr; -} - -template <typename Derived> struct null_chrono_spec_handler { - FMT_CONSTEXPR void unsupported() { - static_cast<Derived*>(this)->unsupported(); - } - FMT_CONSTEXPR void on_year(numeric_system, pad_type) { unsupported(); } - FMT_CONSTEXPR void on_short_year(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_offset_year() { unsupported(); } - FMT_CONSTEXPR void on_century(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_iso_week_based_year() { unsupported(); } - FMT_CONSTEXPR void on_iso_week_based_short_year() { 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_dec_month(numeric_system, pad_type) { unsupported(); } - FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type) { - unsupported(); - } - FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type) { - unsupported(); - } - FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type) { - unsupported(); - } - FMT_CONSTEXPR void on_day_of_year(pad_type) { unsupported(); } - FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type) { - 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(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_tz_name() { unsupported(); } -}; - -struct tm_format_checker : null_chrono_spec_handler<tm_format_checker> { - FMT_NORETURN inline void unsupported() { - FMT_THROW(format_error("no format")); - } - - template <typename Char> - FMT_CONSTEXPR void on_text(const Char*, const Char*) {} - FMT_CONSTEXPR void on_year(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_short_year(numeric_system) {} - FMT_CONSTEXPR void on_offset_year() {} - FMT_CONSTEXPR void on_century(numeric_system) {} - FMT_CONSTEXPR void on_iso_week_based_year() {} - FMT_CONSTEXPR void on_iso_week_based_short_year() {} - FMT_CONSTEXPR void on_abbr_weekday() {} - FMT_CONSTEXPR void on_full_weekday() {} - FMT_CONSTEXPR void on_dec0_weekday(numeric_system) {} - FMT_CONSTEXPR void on_dec1_weekday(numeric_system) {} - FMT_CONSTEXPR void on_abbr_month() {} - FMT_CONSTEXPR void on_full_month() {} - FMT_CONSTEXPR void on_dec_month(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_day_of_year(pad_type) {} - FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_second(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_datetime(numeric_system) {} - FMT_CONSTEXPR void on_loc_date(numeric_system) {} - FMT_CONSTEXPR void on_loc_time(numeric_system) {} - FMT_CONSTEXPR void on_us_date() {} - FMT_CONSTEXPR void on_iso_date() {} - 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_utc_offset(numeric_system) {} - FMT_CONSTEXPR void on_tz_name() {} -}; - -inline auto tm_wday_full_name(int wday) -> const char* { - static constexpr const char* full_name_list[] = { - "Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday"}; - return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?"; -} -inline auto tm_wday_short_name(int wday) -> const char* { - static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed", - "Thu", "Fri", "Sat"}; - return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???"; -} - -inline auto tm_mon_full_name(int mon) -> const char* { - static constexpr const char* full_name_list[] = { - "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December"}; - return mon >= 0 && mon <= 11 ? full_name_list[mon] : "?"; -} -inline auto tm_mon_short_name(int mon) -> const char* { - static constexpr const char* short_name_list[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - }; - return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???"; -} - -template <typename T, typename = void> -struct has_member_data_tm_gmtoff : std::false_type {}; -template <typename T> -struct has_member_data_tm_gmtoff<T, void_t<decltype(T::tm_gmtoff)>> - : std::true_type {}; - -template <typename T, typename = void> -struct has_member_data_tm_zone : std::false_type {}; -template <typename T> -struct has_member_data_tm_zone<T, void_t<decltype(T::tm_zone)>> - : std::true_type {}; - -inline void tzset_once() { - static bool init = []() { - using namespace fmt_detail; - _tzset(); - return false; - }(); - ignore_unused(init); -} - -// Converts value to Int and checks that it's in the range [0, upper). -template <typename T, typename Int, FMT_ENABLE_IF(std::is_integral<T>::value)> -inline auto to_nonnegative_int(T value, Int upper) -> Int { - if (!std::is_unsigned<Int>::value && - (value < 0 || to_unsigned(value) > to_unsigned(upper))) { - FMT_THROW(fmt::format_error("chrono value is out of range")); - } - return static_cast<Int>(value); -} -template <typename T, typename Int, FMT_ENABLE_IF(!std::is_integral<T>::value)> -inline auto to_nonnegative_int(T value, Int upper) -> Int { - auto int_value = static_cast<Int>(value); - if (int_value < 0 || value > static_cast<T>(upper)) - FMT_THROW(format_error("invalid value")); - return int_value; -} - -constexpr auto pow10(std::uint32_t n) -> long long { - return n == 0 ? 1 : 10 * pow10(n - 1); -} - -// Counts the number of fractional digits in the range [0, 18] according to the -// C++20 spec. If more than 18 fractional digits are required then returns 6 for -// microseconds precision. -template <long long Num, long long Den, int N = 0, - bool Enabled = (N < 19) && (Num <= max_value<long long>() / 10)> -struct count_fractional_digits { - static constexpr int value = - Num % Den == 0 ? N : count_fractional_digits<Num * 10, Den, N + 1>::value; -}; - -// Base case that doesn't instantiate any more templates -// in order to avoid overflow. -template <long long Num, long long Den, int N> -struct count_fractional_digits<Num, Den, N, false> { - static constexpr int value = (Num % Den == 0) ? N : 6; -}; - -// Format subseconds which are given as an integer type with an appropriate -// number of digits. -template <typename Char, typename OutputIt, typename Duration> -void write_fractional_seconds(OutputIt& out, Duration d, int precision = -1) { - constexpr auto num_fractional_digits = - count_fractional_digits<Duration::period::num, - Duration::period::den>::value; - - using subsecond_precision = std::chrono::duration< - typename std::common_type<typename Duration::rep, - std::chrono::seconds::rep>::type, - std::ratio<1, pow10(num_fractional_digits)>>; - - const auto fractional = d - detail::duration_cast<std::chrono::seconds>(d); - const auto subseconds = - std::chrono::treat_as_floating_point< - typename subsecond_precision::rep>::value - ? fractional.count() - : detail::duration_cast<subsecond_precision>(fractional).count(); - auto n = static_cast<uint32_or_64_or_128_t<long long>>(subseconds); - const int num_digits = count_digits(n); - - int leading_zeroes = (std::max)(0, num_fractional_digits - num_digits); - if (precision < 0) { - FMT_ASSERT(!std::is_floating_point<typename Duration::rep>::value, ""); - if (std::ratio_less<typename subsecond_precision::period, - std::chrono::seconds::period>::value) { - *out++ = '.'; - out = detail::fill_n(out, leading_zeroes, '0'); - out = format_decimal<Char>(out, n, num_digits); - } - } else if (precision > 0) { - *out++ = '.'; - leading_zeroes = min_of(leading_zeroes, precision); - int remaining = precision - leading_zeroes; - out = detail::fill_n(out, leading_zeroes, '0'); - if (remaining < num_digits) { - int num_truncated_digits = num_digits - remaining; - n /= to_unsigned(pow10(to_unsigned(num_truncated_digits))); - if (n != 0) out = format_decimal<Char>(out, n, remaining); - return; - } - if (n != 0) { - out = format_decimal<Char>(out, n, num_digits); - remaining -= num_digits; - } - out = detail::fill_n(out, remaining, '0'); - } -} - -// Format subseconds which are given as a floating point type with an -// appropriate number of digits. We cannot pass the Duration here, as we -// explicitly need to pass the Rep value in the chrono_formatter. -template <typename Duration> -void write_floating_seconds(memory_buffer& buf, Duration duration, - int num_fractional_digits = -1) { - using rep = typename Duration::rep; - FMT_ASSERT(std::is_floating_point<rep>::value, ""); - - auto val = duration.count(); - - if (num_fractional_digits < 0) { - // For `std::round` with fallback to `round`: - // On some toolchains `std::round` is not available (e.g. GCC 6). - using namespace std; - num_fractional_digits = - count_fractional_digits<Duration::period::num, - Duration::period::den>::value; - if (num_fractional_digits < 6 && static_cast<rep>(round(val)) != val) - num_fractional_digits = 6; - } - - fmt::format_to(std::back_inserter(buf), FMT_STRING("{:.{}f}"), - std::fmod(val * static_cast<rep>(Duration::period::num) / - static_cast<rep>(Duration::period::den), - static_cast<rep>(60)), - num_fractional_digits); -} - -template <typename OutputIt, typename Char, - typename Duration = std::chrono::seconds> -class tm_writer { - private: - static constexpr int days_per_week = 7; - - const std::locale& loc_; - const bool is_classic_; - OutputIt out_; - const Duration* subsecs_; - const std::tm& tm_; - - auto tm_sec() const noexcept -> int { - FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61, ""); - return tm_.tm_sec; - } - auto tm_min() const noexcept -> int { - FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59, ""); - return tm_.tm_min; - } - auto tm_hour() const noexcept -> int { - FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23, ""); - return tm_.tm_hour; - } - auto tm_mday() const noexcept -> int { - FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31, ""); - return tm_.tm_mday; - } - auto tm_mon() const noexcept -> int { - FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11, ""); - return tm_.tm_mon; - } - auto tm_year() const noexcept -> long long { return 1900ll + tm_.tm_year; } - auto tm_wday() const noexcept -> int { - FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6, ""); - return tm_.tm_wday; - } - auto tm_yday() const noexcept -> int { - FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365, ""); - return tm_.tm_yday; - } - - auto tm_hour12() const noexcept -> int { - const auto h = tm_hour(); - const auto z = h < 12 ? h : h - 12; - return z == 0 ? 12 : z; - } - - // POSIX and the C Standard are unclear or inconsistent about what %C and %y - // do if the year is negative or exceeds 9999. Use the convention that %C - // concatenated with %y yields the same output as %Y, and that %Y contains at - // least 4 characters, with more only if necessary. - auto split_year_lower(long long year) const noexcept -> int { - auto l = year % 100; - if (l < 0) l = -l; // l in [0, 99] - return static_cast<int>(l); - } - - // Algorithm: https://en.wikipedia.org/wiki/ISO_week_date. - auto iso_year_weeks(long long curr_year) const noexcept -> int { - const auto prev_year = curr_year - 1; - const auto curr_p = - (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) % - days_per_week; - const auto prev_p = - (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) % - days_per_week; - return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0); - } - auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int { - return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) / - days_per_week; - } - auto tm_iso_week_year() const noexcept -> long long { - const auto year = tm_year(); - const auto w = iso_week_num(tm_yday(), tm_wday()); - if (w < 1) return year - 1; - if (w > iso_year_weeks(year)) return year + 1; - return year; - } - auto tm_iso_week_of_year() const noexcept -> int { - const auto year = tm_year(); - const auto w = iso_week_num(tm_yday(), tm_wday()); - if (w < 1) return iso_year_weeks(year - 1); - if (w > iso_year_weeks(year)) return 1; - return w; - } - - void write1(int value) { - *out_++ = static_cast<char>('0' + to_unsigned(value) % 10); - } - void write2(int value) { - const char* d = digits2(to_unsigned(value) % 100); - *out_++ = *d++; - *out_++ = *d; - } - void write2(int value, pad_type pad) { - unsigned int v = to_unsigned(value) % 100; - if (v >= 10) { - const char* d = digits2(v); - *out_++ = *d++; - *out_++ = *d; - } else { - out_ = detail::write_padding(out_, pad); - *out_++ = static_cast<char>('0' + v); - } - } - - void write_year_extended(long long year, pad_type pad) { - // At least 4 characters. - int width = 4; - bool negative = year < 0; - if (negative) { - year = 0 - year; - --width; - } - uint32_or_64_or_128_t<long long> n = to_unsigned(year); - const int num_digits = count_digits(n); - if (negative && pad == pad_type::zero) *out_++ = '-'; - if (width > num_digits) { - out_ = detail::write_padding(out_, pad, width - num_digits); - } - if (negative && pad != pad_type::zero) *out_++ = '-'; - out_ = format_decimal<Char>(out_, n, num_digits); - } - void write_year(long long year, pad_type pad) { - write_year_extended(year, pad); - } - - void write_utc_offset(long long offset, numeric_system ns) { - if (offset < 0) { - *out_++ = '-'; - offset = -offset; - } else { - *out_++ = '+'; - } - offset /= 60; - write2(static_cast<int>(offset / 60)); - if (ns != numeric_system::standard) *out_++ = ':'; - write2(static_cast<int>(offset % 60)); - } - - template <typename T, FMT_ENABLE_IF(has_member_data_tm_gmtoff<T>::value)> - void format_utc_offset_impl(const T& tm, numeric_system ns) { - write_utc_offset(tm.tm_gmtoff, ns); - } - template <typename T, FMT_ENABLE_IF(!has_member_data_tm_gmtoff<T>::value)> - void format_utc_offset_impl(const T& tm, numeric_system ns) { -#if defined(_WIN32) && defined(_UCRT) - tzset_once(); - long offset = 0; - _get_timezone(&offset); - if (tm.tm_isdst) { - long dstbias = 0; - _get_dstbias(&dstbias); - offset += dstbias; - } - write_utc_offset(-offset, ns); -#else - if (ns == numeric_system::standard) return format_localized('z'); - - // Extract timezone offset from timezone conversion functions. - std::tm gtm = tm; - std::time_t gt = std::mktime(>m); - std::tm ltm = gmtime(gt); - std::time_t lt = std::mktime(<m); - long long offset = gt - lt; - write_utc_offset(offset, ns); -#endif - } - - template <typename T, FMT_ENABLE_IF(has_member_data_tm_zone<T>::value)> - void format_tz_name_impl(const T& tm) { - if (is_classic_) - out_ = write_tm_str<Char>(out_, tm.tm_zone, loc_); - else - format_localized('Z'); - } - template <typename T, FMT_ENABLE_IF(!has_member_data_tm_zone<T>::value)> - void format_tz_name_impl(const T&) { - format_localized('Z'); - } - - void format_localized(char format, char modifier = 0) { - out_ = write<Char>(out_, tm_, loc_, format, modifier); - } - - public: - tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm, - const Duration* subsecs = nullptr) - : loc_(loc), - is_classic_(loc_ == get_classic_locale()), - out_(out), - subsecs_(subsecs), - tm_(tm) {} - - auto out() const -> OutputIt { return out_; } - - FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { - out_ = copy<Char>(begin, end, out_); - } - - void on_abbr_weekday() { - if (is_classic_) - out_ = write(out_, tm_wday_short_name(tm_wday())); - else - format_localized('a'); - } - void on_full_weekday() { - if (is_classic_) - out_ = write(out_, tm_wday_full_name(tm_wday())); - else - format_localized('A'); - } - void on_dec0_weekday(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) return write1(tm_wday()); - format_localized('w', 'O'); - } - void on_dec1_weekday(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) { - auto wday = tm_wday(); - write1(wday == 0 ? days_per_week : wday); - } else { - format_localized('u', 'O'); - } - } - - void on_abbr_month() { - if (is_classic_) - out_ = write(out_, tm_mon_short_name(tm_mon())); - else - format_localized('b'); - } - void on_full_month() { - if (is_classic_) - out_ = write(out_, tm_mon_full_name(tm_mon())); - else - format_localized('B'); - } - - void on_datetime(numeric_system ns) { - if (is_classic_) { - on_abbr_weekday(); - *out_++ = ' '; - on_abbr_month(); - *out_++ = ' '; - on_day_of_month(numeric_system::standard, pad_type::space); - *out_++ = ' '; - on_iso_time(); - *out_++ = ' '; - on_year(numeric_system::standard, pad_type::space); - } else { - format_localized('c', ns == numeric_system::standard ? '\0' : 'E'); - } - } - void on_loc_date(numeric_system ns) { - if (is_classic_) - on_us_date(); - else - format_localized('x', ns == numeric_system::standard ? '\0' : 'E'); - } - void on_loc_time(numeric_system ns) { - if (is_classic_) - on_iso_time(); - else - format_localized('X', ns == numeric_system::standard ? '\0' : 'E'); - } - void on_us_date() { - char buf[8]; - write_digit2_separated(buf, to_unsigned(tm_mon() + 1), - to_unsigned(tm_mday()), - to_unsigned(split_year_lower(tm_year())), '/'); - out_ = copy<Char>(std::begin(buf), std::end(buf), out_); - } - void on_iso_date() { - auto year = tm_year(); - char buf[10]; - size_t offset = 0; - if (year >= 0 && year < 10000) { - write2digits(buf, static_cast<size_t>(year / 100)); - } else { - offset = 4; - write_year_extended(year, pad_type::zero); - year = 0; - } - write_digit2_separated(buf + 2, static_cast<unsigned>(year % 100), - to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()), - '-'); - out_ = copy<Char>(std::begin(buf) + offset, std::end(buf), out_); - } - - void on_utc_offset(numeric_system ns) { format_utc_offset_impl(tm_, ns); } - void on_tz_name() { format_tz_name_impl(tm_); } - - void on_year(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) - return write_year(tm_year(), pad); - format_localized('Y', 'E'); - } - void on_short_year(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) - return write2(split_year_lower(tm_year())); - format_localized('y', 'O'); - } - void on_offset_year() { - if (is_classic_) return write2(split_year_lower(tm_year())); - format_localized('y', 'E'); - } - - void on_century(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) { - auto year = tm_year(); - auto upper = year / 100; - if (year >= -99 && year < 0) { - // Zero upper on negative year. - *out_++ = '-'; - *out_++ = '0'; - } else if (upper >= 0 && upper < 100) { - write2(static_cast<int>(upper)); - } else { - out_ = write<Char>(out_, upper); - } - } else { - format_localized('C', 'E'); - } - } - - void on_dec_month(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) - return write2(tm_mon() + 1, pad); - format_localized('m', 'O'); - } - - void on_dec0_week_of_year(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) - return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week, - pad); - format_localized('U', 'O'); - } - void on_dec1_week_of_year(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) { - auto wday = tm_wday(); - write2((tm_yday() + days_per_week - - (wday == 0 ? (days_per_week - 1) : (wday - 1))) / - days_per_week, - pad); - } else { - format_localized('W', 'O'); - } - } - void on_iso_week_of_year(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) - return write2(tm_iso_week_of_year(), pad); - format_localized('V', 'O'); - } - - void on_iso_week_based_year() { - write_year(tm_iso_week_year(), pad_type::zero); - } - void on_iso_week_based_short_year() { - write2(split_year_lower(tm_iso_week_year())); - } - - void on_day_of_year(pad_type pad) { - auto yday = tm_yday() + 1; - auto digit1 = yday / 100; - if (digit1 != 0) { - write1(digit1); - } else { - out_ = detail::write_padding(out_, pad); - } - write2(yday % 100, pad); - } - - void on_day_of_month(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) - return write2(tm_mday(), pad); - format_localized('d', 'O'); - } - - void on_24_hour(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) - return write2(tm_hour(), pad); - format_localized('H', 'O'); - } - void on_12_hour(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) - return write2(tm_hour12(), pad); - format_localized('I', 'O'); - } - void on_minute(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) - return write2(tm_min(), pad); - format_localized('M', 'O'); - } - - void on_second(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) { - write2(tm_sec(), pad); - if (subsecs_) { - if (std::is_floating_point<typename Duration::rep>::value) { - auto buf = memory_buffer(); - write_floating_seconds(buf, *subsecs_); - if (buf.size() > 1) { - // Remove the leading "0", write something like ".123". - out_ = copy<Char>(buf.begin() + 1, buf.end(), out_); - } - } else { - write_fractional_seconds<Char>(out_, *subsecs_); - } - } - } else { - // Currently no formatting of subseconds when a locale is set. - format_localized('S', 'O'); - } - } - - void on_12_hour_time() { - if (is_classic_) { - char buf[8]; - write_digit2_separated(buf, to_unsigned(tm_hour12()), - to_unsigned(tm_min()), to_unsigned(tm_sec()), ':'); - out_ = copy<Char>(std::begin(buf), std::end(buf), out_); - *out_++ = ' '; - on_am_pm(); - } else { - format_localized('r'); - } - } - void on_24_hour_time() { - write2(tm_hour()); - *out_++ = ':'; - write2(tm_min()); - } - void on_iso_time() { - on_24_hour_time(); - *out_++ = ':'; - on_second(numeric_system::standard, pad_type::zero); - } - - void on_am_pm() { - if (is_classic_) { - *out_++ = tm_hour() < 12 ? 'A' : 'P'; - *out_++ = 'M'; - } else { - format_localized('p'); - } - } - - // These apply to chrono durations but not tm. - void on_duration_value() {} - void on_duration_unit() {} -}; - -struct chrono_format_checker : null_chrono_spec_handler<chrono_format_checker> { - bool has_precision_integral = false; - - FMT_NORETURN inline void unsupported() { FMT_THROW(format_error("no date")); } - - template <typename Char> - FMT_CONSTEXPR void on_text(const Char*, const Char*) {} - FMT_CONSTEXPR void on_day_of_year(pad_type) {} - FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_second(numeric_system, pad_type) {} - 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() const { - if (has_precision_integral) - FMT_THROW(format_error("precision not allowed for this argument type")); - } - FMT_CONSTEXPR void on_duration_unit() {} -}; - -template <typename T, - FMT_ENABLE_IF(std::is_integral<T>::value&& has_isfinite<T>::value)> -inline auto isfinite(T) -> bool { - return true; -} - -template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> -inline auto mod(T x, int y) -> T { - return x % static_cast<T>(y); -} -template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> -inline auto mod(T x, int y) -> T { - return std::fmod(x, static_cast<T>(y)); -} - -// If T is an integral type, maps T to its unsigned counterpart, otherwise -// leaves it unchanged (unlike std::make_unsigned). -template <typename T, bool INTEGRAL = std::is_integral<T>::value> -struct make_unsigned_or_unchanged { - using type = T; -}; - -template <typename T> struct make_unsigned_or_unchanged<T, true> { - using type = typename std::make_unsigned<T>::type; -}; - -template <typename Rep, typename Period, - FMT_ENABLE_IF(std::is_integral<Rep>::value)> -inline auto get_milliseconds(std::chrono::duration<Rep, Period> d) - -> std::chrono::duration<Rep, std::milli> { - // this may overflow and/or the result may not fit in the - // target type. -#if FMT_SAFE_DURATION_CAST - using CommonSecondsType = - typename std::common_type<decltype(d), std::chrono::seconds>::type; - const auto d_as_common = detail::duration_cast<CommonSecondsType>(d); - const auto d_as_whole_seconds = - detail::duration_cast<std::chrono::seconds>(d_as_common); - // this conversion should be nonproblematic - const auto diff = d_as_common - d_as_whole_seconds; - const auto ms = - detail::duration_cast<std::chrono::duration<Rep, std::milli>>(diff); - return ms; -#else - auto s = detail::duration_cast<std::chrono::seconds>(d); - return detail::duration_cast<std::chrono::milliseconds>(d - s); -#endif -} - -template <typename Char, typename Rep, typename OutputIt, - FMT_ENABLE_IF(std::is_integral<Rep>::value)> -auto format_duration_value(OutputIt out, Rep val, int) -> OutputIt { - return write<Char>(out, val); -} - -template <typename Char, typename Rep, typename OutputIt, - FMT_ENABLE_IF(std::is_floating_point<Rep>::value)> -auto format_duration_value(OutputIt out, Rep val, int precision) -> OutputIt { - auto specs = format_specs(); - specs.precision = precision; - specs.set_type(precision >= 0 ? presentation_type::fixed - : presentation_type::general); - return write<Char>(out, val, specs); -} - -template <typename Char, typename OutputIt> -auto copy_unit(string_view unit, OutputIt out, Char) -> OutputIt { - return copy<Char>(unit.begin(), unit.end(), out); -} - -template <typename OutputIt> -auto copy_unit(string_view unit, OutputIt out, wchar_t) -> OutputIt { - // This works when wchar_t is UTF-32 because units only contain characters - // that have the same representation in UTF-16 and UTF-32. - utf8_to_utf16 u(unit); - return copy<wchar_t>(u.c_str(), u.c_str() + u.size(), out); -} - -template <typename Char, typename Period, typename OutputIt> -auto format_duration_unit(OutputIt out) -> OutputIt { - if (const char* unit = get_units<Period>()) - return copy_unit(string_view(unit), out, Char()); - *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; -} - -class get_locale { - private: - union { - std::locale locale_; - }; - bool has_locale_ = false; - - public: - inline get_locale(bool localized, locale_ref loc) : has_locale_(localized) { - if (localized) - ::new (&locale_) std::locale(loc.template get<std::locale>()); - } - inline ~get_locale() { - if (has_locale_) locale_.~locale(); - } - inline operator const std::locale&() const { - return has_locale_ ? locale_ : get_classic_locale(); - } -}; - -template <typename FormatContext, typename OutputIt, typename Rep, - typename Period> -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), - unsigned, typename make_unsigned_or_unchanged<Rep>::type>; - rep val; - using seconds = std::chrono::duration<rep>; - seconds s; - using milliseconds = std::chrono::duration<rep, std::milli>; - bool negative; - - using char_type = typename FormatContext::char_type; - using tm_writer_type = tm_writer<OutputIt, char_type>; - - chrono_formatter(FormatContext& ctx, OutputIt o, - std::chrono::duration<Rep, Period> d) - : context(ctx), - out(o), - val(static_cast<rep>(d.count())), - negative(false) { - if (d.count() < 0) { - val = 0 - val; - negative = true; - } - - // this may overflow and/or the result may not fit in the - // target type. - // might need checked conversion (rep!=Rep) - s = detail::duration_cast<seconds>(std::chrono::duration<rep, Period>(val)); - } - - // returns true if nan or inf, writes to out. - auto handle_nan_inf() -> bool { - if (isfinite(val)) { - return false; - } - if (isnan(val)) { - write_nan(); - return true; - } - // must be +-inf - if (val > 0) { - write_pinf(); - } else { - write_ninf(); - } - return true; - } - - auto days() const -> Rep { return static_cast<Rep>(s.count() / 86400); } - auto hour() const -> Rep { - return static_cast<Rep>(mod((s.count() / 3600), 24)); - } - - auto hour12() const -> Rep { - Rep hour = static_cast<Rep>(mod((s.count() / 3600), 12)); - return hour <= 0 ? 12 : hour; - } - - auto minute() const -> Rep { - return static_cast<Rep>(mod((s.count() / 60), 60)); - } - auto second() const -> Rep { return static_cast<Rep>(mod(s.count(), 60)); } - - auto time() const -> std::tm { - auto time = std::tm(); - time.tm_hour = to_nonnegative_int(hour(), 24); - time.tm_min = to_nonnegative_int(minute(), 60); - time.tm_sec = to_nonnegative_int(second(), 60); - return time; - } - - void write_sign() { - if (negative) { - *out++ = '-'; - negative = false; - } - } - - void write(Rep value, int width, pad_type pad = pad_type::zero) { - write_sign(); - if (isnan(value)) return write_nan(); - uint32_or_64_or_128_t<int> n = - to_unsigned(to_nonnegative_int(value, max_value<int>())); - int num_digits = detail::count_digits(n); - if (width > num_digits) { - out = detail::write_padding(out, pad, width - num_digits); - } - out = format_decimal<char_type>(out, n, num_digits); - } - - void write_nan() { std::copy_n("nan", 3, out); } - void write_pinf() { std::copy_n("inf", 3, out); } - void write_ninf() { std::copy_n("-inf", 4, out); } - - template <typename Callback, typename... Args> - void format_tm(const tm& time, Callback cb, Args... args) { - if (isnan(val)) return write_nan(); - get_locale loc(localized, context.locale()); - auto w = tm_writer_type(loc, out, time); - (w.*cb)(args...); - out = w.out(); - } - - void on_text(const char_type* begin, const char_type* end) { - copy<char_type>(begin, end, out); - } - - // These are not implemented because durations don't have date information. - void on_abbr_weekday() {} - void on_full_weekday() {} - void on_dec0_weekday(numeric_system) {} - void on_dec1_weekday(numeric_system) {} - void on_abbr_month() {} - void on_full_month() {} - void on_datetime(numeric_system) {} - void on_loc_date(numeric_system) {} - void on_loc_time(numeric_system) {} - void on_us_date() {} - void on_iso_date() {} - void on_utc_offset(numeric_system) {} - void on_tz_name() {} - void on_year(numeric_system, pad_type) {} - void on_short_year(numeric_system) {} - void on_offset_year() {} - void on_century(numeric_system) {} - void on_iso_week_based_year() {} - void on_iso_week_based_short_year() {} - void on_dec_month(numeric_system, pad_type) {} - void on_dec0_week_of_year(numeric_system, pad_type) {} - void on_dec1_week_of_year(numeric_system, pad_type) {} - void on_iso_week_of_year(numeric_system, pad_type) {} - void on_day_of_month(numeric_system, pad_type) {} - - void on_day_of_year(pad_type) { - if (handle_nan_inf()) return; - write(days(), 0); - } - - void on_24_hour(numeric_system ns, pad_type pad) { - if (handle_nan_inf()) return; - - if (ns == numeric_system::standard) return write(hour(), 2, pad); - auto time = tm(); - time.tm_hour = to_nonnegative_int(hour(), 24); - format_tm(time, &tm_writer_type::on_24_hour, ns, pad); - } - - void on_12_hour(numeric_system ns, pad_type pad) { - if (handle_nan_inf()) return; - - if (ns == numeric_system::standard) return write(hour12(), 2, pad); - auto time = tm(); - time.tm_hour = to_nonnegative_int(hour12(), 12); - format_tm(time, &tm_writer_type::on_12_hour, ns, pad); - } - - void on_minute(numeric_system ns, pad_type pad) { - if (handle_nan_inf()) return; - - if (ns == numeric_system::standard) return write(minute(), 2, pad); - auto time = tm(); - time.tm_min = to_nonnegative_int(minute(), 60); - format_tm(time, &tm_writer_type::on_minute, ns, pad); - } - - void on_second(numeric_system ns, pad_type pad) { - if (handle_nan_inf()) return; - - if (ns == numeric_system::standard) { - if (std::is_floating_point<rep>::value) { - auto buf = memory_buffer(); - write_floating_seconds(buf, std::chrono::duration<rep, Period>(val), - precision); - if (negative) *out++ = '-'; - if (buf.size() < 2 || buf[1] == '.') { - out = detail::write_padding(out, pad); - } - out = copy<char_type>(buf.begin(), buf.end(), out); - } else { - write(second(), 2, pad); - write_fractional_seconds<char_type>( - out, std::chrono::duration<rep, Period>(val), precision); - } - return; - } - auto time = tm(); - time.tm_sec = to_nonnegative_int(second(), 60); - format_tm(time, &tm_writer_type::on_second, ns, pad); - } - - void on_12_hour_time() { - if (handle_nan_inf()) return; - format_tm(time(), &tm_writer_type::on_12_hour_time); - } - - void on_24_hour_time() { - if (handle_nan_inf()) { - *out++ = ':'; - handle_nan_inf(); - return; - } - - write(hour(), 2); - *out++ = ':'; - write(minute(), 2); - } - - void on_iso_time() { - on_24_hour_time(); - *out++ = ':'; - if (handle_nan_inf()) return; - on_second(numeric_system::standard, pad_type::zero); - } - - void on_am_pm() { - if (handle_nan_inf()) return; - format_tm(time(), &tm_writer_type::on_am_pm); - } - - void on_duration_value() { - if (handle_nan_inf()) return; - write_sign(); - out = format_duration_value<char_type>(out, val, precision); - } - - void on_duration_unit() { - out = format_duration_unit<char_type, Period>(out); - } -}; - -} // namespace detail - -#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907 -using weekday = std::chrono::weekday; -using day = std::chrono::day; -using month = std::chrono::month; -using year = std::chrono::year; -using year_month_day = std::chrono::year_month_day; -#else -// A fallback version of weekday. -class weekday { - private: - unsigned char value_; - - public: - weekday() = default; - constexpr explicit weekday(unsigned wd) noexcept - : value_(static_cast<unsigned char>(wd != 7 ? wd : 0)) {} - constexpr auto c_encoding() const noexcept -> unsigned { return value_; } -}; - -class day { - private: - unsigned char value_; - - public: - day() = default; - constexpr explicit day(unsigned d) noexcept - : value_(static_cast<unsigned char>(d)) {} - constexpr explicit operator unsigned() const noexcept { return value_; } -}; - -class month { - private: - unsigned char value_; - - public: - month() = default; - constexpr explicit month(unsigned m) noexcept - : value_(static_cast<unsigned char>(m)) {} - constexpr explicit operator unsigned() const noexcept { return value_; } -}; - -class year { - private: - int value_; - - public: - year() = default; - constexpr explicit year(int y) noexcept : value_(y) {} - constexpr explicit operator int() const noexcept { return value_; } -}; - -class year_month_day { - private: - fmt::year year_; - fmt::month month_; - fmt::day day_; - - public: - year_month_day() = default; - constexpr year_month_day(const year& y, const month& m, const day& d) noexcept - : year_(y), month_(m), day_(d) {} - constexpr auto year() const noexcept -> fmt::year { return year_; } - constexpr auto month() const noexcept -> fmt::month { return month_; } - constexpr auto day() const noexcept -> fmt::day { return day_; } -}; -#endif - -template <typename Char> -struct formatter<weekday, Char> : private formatter<std::tm, Char> { - private: - bool localized_ = false; - bool use_tm_formatter_ = false; - - public: - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - auto it = ctx.begin(), end = ctx.end(); - if (it != end && *it == 'L') { - ++it; - localized_ = true; - return it; - } - use_tm_formatter_ = it != end && *it != '}'; - return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it; - } - - template <typename FormatContext> - auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) { - auto time = std::tm(); - time.tm_wday = static_cast<int>(wd.c_encoding()); - if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx); - detail::get_locale loc(localized_, ctx.locale()); - auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time); - w.on_abbr_weekday(); - return w.out(); - } -}; - -template <typename Char> -struct formatter<day, Char> : private formatter<std::tm, Char> { - private: - bool use_tm_formatter_ = false; - - public: - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - auto it = ctx.begin(), end = ctx.end(); - use_tm_formatter_ = it != end && *it != '}'; - return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it; - } - - template <typename FormatContext> - auto format(day d, FormatContext& ctx) const -> decltype(ctx.out()) { - auto time = std::tm(); - time.tm_mday = static_cast<int>(static_cast<unsigned>(d)); - if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx); - detail::get_locale loc(false, ctx.locale()); - auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time); - w.on_day_of_month(detail::numeric_system::standard, detail::pad_type::zero); - return w.out(); - } -}; - -template <typename Char> -struct formatter<month, Char> : private formatter<std::tm, Char> { - private: - bool localized_ = false; - bool use_tm_formatter_ = false; - - public: - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - auto it = ctx.begin(), end = ctx.end(); - if (it != end && *it == 'L') { - ++it; - localized_ = true; - return it; - } - use_tm_formatter_ = it != end && *it != '}'; - return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it; - } - - template <typename FormatContext> - auto format(month m, FormatContext& ctx) const -> decltype(ctx.out()) { - auto time = std::tm(); - time.tm_mon = static_cast<int>(static_cast<unsigned>(m)) - 1; - if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx); - detail::get_locale loc(localized_, ctx.locale()); - auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time); - w.on_abbr_month(); - return w.out(); - } -}; - -template <typename Char> -struct formatter<year, Char> : private formatter<std::tm, Char> { - private: - bool use_tm_formatter_ = false; - - public: - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - auto it = ctx.begin(), end = ctx.end(); - use_tm_formatter_ = it != end && *it != '}'; - return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it; - } - - template <typename FormatContext> - auto format(year y, FormatContext& ctx) const -> decltype(ctx.out()) { - auto time = std::tm(); - time.tm_year = static_cast<int>(y) - 1900; - if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx); - detail::get_locale loc(false, ctx.locale()); - auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time); - w.on_year(detail::numeric_system::standard, detail::pad_type::zero); - return w.out(); - } -}; - -template <typename Char> -struct formatter<year_month_day, Char> : private formatter<std::tm, Char> { - private: - bool use_tm_formatter_ = false; - - public: - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - auto it = ctx.begin(), end = ctx.end(); - use_tm_formatter_ = it != end && *it != '}'; - return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it; - } - - template <typename FormatContext> - auto format(year_month_day val, FormatContext& ctx) const - -> decltype(ctx.out()) { - auto time = std::tm(); - time.tm_year = static_cast<int>(val.year()) - 1900; - time.tm_mon = static_cast<int>(static_cast<unsigned>(val.month())) - 1; - time.tm_mday = static_cast<int>(static_cast<unsigned>(val.day())); - if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx); - detail::get_locale loc(true, ctx.locale()); - auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time); - w.on_iso_date(); - return w.out(); - } -}; - -template <typename Rep, typename Period, typename Char> -struct formatter<std::chrono::duration<Rep, Period>, Char> { - private: - format_specs specs_; - detail::arg_ref<Char> width_ref_; - detail::arg_ref<Char> precision_ref_; - bool localized_ = false; - basic_string_view<Char> fmt_; - - public: - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - auto it = ctx.begin(), end = ctx.end(); - if (it == end || *it == '}') return it; - - it = detail::parse_align(it, end, specs_); - if (it == end) return it; - - Char c = *it; - if ((c >= '0' && c <= '9') || c == '{') { - it = detail::parse_width(it, end, specs_, width_ref_, ctx); - if (it == end) return it; - } - - auto checker = detail::chrono_format_checker(); - if (*it == '.') { - checker.has_precision_integral = !std::is_floating_point<Rep>::value; - it = detail::parse_precision(it, end, specs_, precision_ref_, ctx); - } - if (it != end && *it == 'L') { - localized_ = true; - ++it; - } - end = detail::parse_chrono_format(it, end, checker); - fmt_ = {it, detail::to_unsigned(end - it)}; - return end; - } - - template <typename FormatContext> - auto format(std::chrono::duration<Rep, Period> d, FormatContext& ctx) const - -> decltype(ctx.out()) { - auto specs = specs_; - auto precision = specs.precision; - specs.precision = -1; - auto begin = fmt_.begin(), end = fmt_.end(); - // As a possible future optimization, we could avoid extra copying if width - // is not specified. - auto buf = basic_memory_buffer<Char>(); - auto out = basic_appender<Char>(buf); - detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, - ctx); - detail::handle_dynamic_spec(specs.dynamic_precision(), precision, - precision_ref_, ctx); - if (begin == end || *begin == '}') { - out = detail::format_duration_value<Char>(out, d.count(), precision); - detail::format_duration_unit<Char, Period>(out); - } else { - using chrono_formatter = - detail::chrono_formatter<FormatContext, decltype(out), Rep, Period>; - auto f = chrono_formatter(ctx, out, d); - f.precision = precision; - f.localized = localized_; - detail::parse_chrono_format(begin, end, f); - } - return detail::write( - ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs); - } -}; - -template <typename Char> struct formatter<std::tm, Char> { - private: - format_specs specs_; - detail::arg_ref<Char> width_ref_; - - protected: - basic_string_view<Char> fmt_; - - template <typename Duration, typename FormatContext> - auto do_format(const std::tm& tm, FormatContext& ctx, - const Duration* subsecs) const -> decltype(ctx.out()) { - auto specs = specs_; - auto buf = basic_memory_buffer<Char>(); - auto out = basic_appender<Char>(buf); - detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, - ctx); - - auto loc_ref = ctx.locale(); - detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref); - auto w = - detail::tm_writer<decltype(out), Char, Duration>(loc, out, tm, subsecs); - detail::parse_chrono_format(fmt_.begin(), fmt_.end(), w); - return detail::write( - ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs); - } - - public: - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - auto it = ctx.begin(), end = ctx.end(); - if (it == end || *it == '}') return it; - - it = detail::parse_align(it, end, specs_); - if (it == end) return it; - - Char c = *it; - if ((c >= '0' && c <= '9') || c == '{') { - it = detail::parse_width(it, end, specs_, width_ref_, ctx); - if (it == end) return it; - } - - end = detail::parse_chrono_format(it, end, detail::tm_format_checker()); - // Replace the default format string only if the new spec is not empty. - if (end != it) fmt_ = {it, detail::to_unsigned(end - it)}; - return end; - } - - template <typename FormatContext> - auto format(const std::tm& tm, FormatContext& ctx) const - -> decltype(ctx.out()) { - return do_format<std::chrono::seconds>(tm, ctx, nullptr); - } -}; - -template <typename Char, typename Duration> -struct formatter<sys_time<Duration>, Char> : formatter<std::tm, Char> { - FMT_CONSTEXPR formatter() { - this->fmt_ = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>(); - } - - template <typename FormatContext> - auto format(sys_time<Duration> val, FormatContext& ctx) const - -> decltype(ctx.out()) { - std::tm tm = gmtime(val); - using period = typename Duration::period; - if (detail::const_check( - period::num == 1 && period::den == 1 && - !std::is_floating_point<typename Duration::rep>::value)) { - return formatter<std::tm, Char>::format(tm, ctx); - } - Duration epoch = val.time_since_epoch(); - Duration subsecs = detail::duration_cast<Duration>( - epoch - detail::duration_cast<std::chrono::seconds>(epoch)); - if (subsecs.count() < 0) { - auto second = detail::duration_cast<Duration>(std::chrono::seconds(1)); - if (tm.tm_sec != 0) - --tm.tm_sec; - else - tm = gmtime(val - second); - subsecs += detail::duration_cast<Duration>(std::chrono::seconds(1)); - } - return formatter<std::tm, Char>::do_format(tm, ctx, &subsecs); - } -}; - -template <typename Duration, typename Char> -struct formatter<utc_time<Duration>, Char> - : formatter<sys_time<Duration>, Char> { - template <typename FormatContext> - auto format(utc_time<Duration> val, FormatContext& ctx) const - -> decltype(ctx.out()) { - return formatter<sys_time<Duration>, Char>::format( - detail::utc_clock::to_sys(val), ctx); - } -}; - -template <typename Duration, typename Char> -struct formatter<local_time<Duration>, Char> : formatter<std::tm, Char> { - FMT_CONSTEXPR formatter() { - this->fmt_ = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>(); - } - - template <typename FormatContext> - auto format(local_time<Duration> val, FormatContext& ctx) const - -> decltype(ctx.out()) { - using period = typename Duration::period; - if (period::num == 1 && period::den == 1 && - !std::is_floating_point<typename Duration::rep>::value) { - return formatter<std::tm, Char>::format(localtime(val), ctx); - } - auto epoch = val.time_since_epoch(); - auto subsecs = detail::duration_cast<Duration>( - epoch - detail::duration_cast<std::chrono::seconds>(epoch)); - return formatter<std::tm, Char>::do_format(localtime(val), ctx, &subsecs); - } -}; - -FMT_END_EXPORT -FMT_END_NAMESPACE - -#endif // FMT_CHRONO_H_ diff --git a/vendor/fmt/os.h b/vendor/fmt/os.h deleted file mode 100644 index b2cc5e4b8..000000000 --- a/vendor/fmt/os.h +++ /dev/null @@ -1,427 +0,0 @@ -// Formatting library for C++ - optional OS-specific functionality -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_OS_H_ -#define FMT_OS_H_ - -#include "format.h" - -#ifndef FMT_MODULE -# include <cerrno> -# include <cstddef> -# include <cstdio> -# include <system_error> // std::system_error - -# if FMT_HAS_INCLUDE(<xlocale.h>) -# include <xlocale.h> // LC_NUMERIC_MASK on macOS -# endif -#endif // FMT_MODULE - -#ifndef FMT_USE_FCNTL -// UWP doesn't provide _pipe. -# if FMT_HAS_INCLUDE("winapifamily.h") -# include <winapifamily.h> -# endif -# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \ - defined(__linux__)) && \ - (!defined(WINAPI_FAMILY) || \ - (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) -# include <fcntl.h> // for O_RDONLY -# define FMT_USE_FCNTL 1 -# else -# define FMT_USE_FCNTL 0 -# endif -#endif - -#ifndef FMT_POSIX -# if defined(_WIN32) && !defined(__MINGW32__) -// Fix warnings about deprecated symbols. -# define FMT_POSIX(call) _##call -# else -# define FMT_POSIX(call) call -# endif -#endif - -// Calls to system functions are wrapped in FMT_SYSTEM for testability. -#ifdef FMT_SYSTEM -# define FMT_HAS_SYSTEM -# define FMT_POSIX_CALL(call) FMT_SYSTEM(call) -#else -# define FMT_SYSTEM(call) ::call -# ifdef _WIN32 -// Fix warnings about deprecated symbols. -# define FMT_POSIX_CALL(call) ::_##call -# else -# define FMT_POSIX_CALL(call) ::call -# endif -#endif - -// Retries the expression while it evaluates to error_result and errno -// equals to EINTR. -#ifndef _WIN32 -# define FMT_RETRY_VAL(result, expression, error_result) \ - do { \ - (result) = (expression); \ - } while ((result) == (error_result) && errno == EINTR) -#else -# define FMT_RETRY_VAL(result, expression, error_result) result = (expression) -#endif - -#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) - -FMT_BEGIN_NAMESPACE -FMT_BEGIN_EXPORT - -/** - * A reference to a null-terminated string. It can be constructed from a C - * string or `std::string`. - * - * You can use one of the following type aliases for common character types: - * - * +---------------+-----------------------------+ - * | Type | Definition | - * +===============+=============================+ - * | cstring_view | basic_cstring_view<char> | - * +---------------+-----------------------------+ - * | wcstring_view | basic_cstring_view<wchar_t> | - * +---------------+-----------------------------+ - * - * This class is most useful as a parameter type for functions that wrap C APIs. - */ -template <typename Char> class basic_cstring_view { - private: - const Char* data_; - - public: - /// Constructs a string reference object from a C string. - basic_cstring_view(const Char* s) : data_(s) {} - - /// Constructs a string reference from an `std::string` object. - basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {} - - /// Returns the pointer to a C string. - auto c_str() const -> const Char* { return data_; } -}; - -using cstring_view = basic_cstring_view<char>; -using wcstring_view = basic_cstring_view<wchar_t>; - -#ifdef _WIN32 -FMT_API const std::error_category& system_category() noexcept; - -namespace detail { -FMT_API void format_windows_error(buffer<char>& out, int error_code, - const char* message) noexcept; -} - -FMT_API std::system_error vwindows_error(int error_code, string_view fmt, - format_args args); - -/** - * Constructs a `std::system_error` object with the description of the form - * - * <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); - * } - */ -template <typename... T> -auto windows_error(int error_code, string_view message, const T&... args) - -> std::system_error { - return vwindows_error(error_code, message, vargs<T...>{{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, const char* message) noexcept; -#else -inline auto system_category() noexcept -> const std::error_category& { - 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& fmt, Args&&... args) { - std::system(format("say \"{}\"", format(fmt, args...)).c_str()); -} -#endif - -// A buffered file. -class buffered_file { - private: - FILE* file_; - - friend class file; - - inline explicit buffered_file(FILE* f) : file_(f) {} - - public: - buffered_file(const buffered_file&) = delete; - void operator=(const buffered_file&) = delete; - - // Constructs a buffered_file object which doesn't represent any file. - inline buffered_file() noexcept : file_(nullptr) {} - - // Destroys the object closing the file it represents if any. - FMT_API ~buffered_file() noexcept; - - public: - inline buffered_file(buffered_file&& other) noexcept : file_(other.file_) { - other.file_ = nullptr; - } - - inline auto operator=(buffered_file&& other) -> buffered_file& { - close(); - file_ = other.file_; - other.file_ = nullptr; - return *this; - } - - // Opens a file. - FMT_API buffered_file(cstring_view filename, cstring_view mode); - - // Closes the file. - FMT_API void close(); - - // Returns the pointer to a FILE object representing this file. - inline auto get() const noexcept -> FILE* { return file_; } - - FMT_API auto descriptor() const -> int; - - template <typename... T> - inline void print(string_view fmt, const T&... args) { - fmt::vargs<T...> vargs = {{args...}}; - detail::is_locking<T...>() ? fmt::vprint_buffered(file_, fmt, vargs) - : fmt::vprint(file_, fmt, vargs); - } -}; - -#if FMT_USE_FCNTL - -// A file. Closed file is represented by a file object with descriptor -1. -// Methods that are not declared with noexcept may throw -// fmt::system_error in case of failure. Note that some errors such as -// closing the file multiple times will cause a crash on Windows rather -// than an exception. You can get standard behavior by overriding the -// invalid parameter handler with _set_invalid_parameter_handler. -class FMT_API file { - private: - int fd_; // File descriptor. - - // Constructs a file object with a given descriptor. - explicit file(int fd) : fd_(fd) {} - - friend struct pipe; - - public: - // Possible values for the oflag argument to the constructor. - enum { - RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. - 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. - TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file. - }; - - // Constructs a file object which doesn't represent any file. - inline file() noexcept : fd_(-1) {} - - // Opens a file and constructs a file object representing this file. - file(cstring_view path, int oflag); - - public: - file(const file&) = delete; - void operator=(const file&) = delete; - - inline file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } - - // Move assignment is not noexcept because close may throw. - inline auto operator=(file&& other) -> file& { - close(); - fd_ = other.fd_; - other.fd_ = -1; - return *this; - } - - // Destroys the object closing the file it represents if any. - ~file() noexcept; - - // Returns the file descriptor. - inline auto descriptor() const noexcept -> int { return fd_; } - - // Closes the file. - void close(); - - // Returns the file size. The size has signed type for consistency with - // stat::st_size. - auto size() const -> long long; - - // Attempts to read count bytes from the file into the specified buffer. - auto read(void* buffer, size_t count) -> size_t; - - // Attempts to write count bytes from the specified buffer to the file. - auto write(const void* buffer, size_t count) -> size_t; - - // Duplicates a file descriptor with the dup function and returns - // the duplicate as a file object. - static auto dup(int fd) -> file; - - // Makes fd be the copy of this file descriptor, closing fd first if - // necessary. - void dup2(int fd); - - // Makes fd be the copy of this file descriptor, closing fd first if - // necessary. - void dup2(int fd, std::error_code& ec) noexcept; - - // Creates a buffered_file object associated with this file and detaches - // this file object from the file. - auto fdopen(const char* mode) -> buffered_file; - -# if defined(_WIN32) && !defined(__MINGW32__) - // Opens a file and constructs a file object representing this file by - // wcstring_view filename. Windows only. - static file open_windows_file(wcstring_view path, int oflag); -# endif -}; - -struct FMT_API pipe { - file read_end; - file write_end; - - // Creates a pipe setting up read_end and write_end file objects for reading - // and writing respectively. - pipe(); -}; - -// Returns the memory page size. -auto getpagesize() -> long; - -namespace detail { - -struct buffer_size { - constexpr buffer_size() = default; - size_t value = 0; - FMT_CONSTEXPR auto operator=(size_t val) const -> buffer_size { - auto bs = buffer_size(); - bs.value = val; - return bs; - } -}; - -struct ostream_params { - int oflag = file::WRONLY | file::CREATE | file::TRUNC; - size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; - - constexpr ostream_params() {} - - template <typename... T> - ostream_params(T... params, int new_oflag) : ostream_params(params...) { - oflag = new_oflag; - } - - template <typename... T> - ostream_params(T... params, detail::buffer_size bs) - : ostream_params(params...) { - this->buffer_size = bs.value; - } - -// Intel has a bug that results in failure to deduce a constructor -// for empty parameter packs. -# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000 - ostream_params(int new_oflag) : oflag(new_oflag) {} - ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {} -# endif -}; - -} // namespace detail - -FMT_INLINE_VARIABLE constexpr auto buffer_size = detail::buffer_size(); - -/// A fast buffered output stream for writing from a single thread. Writing from -/// multiple threads without external synchronization may result in a data race. -class FMT_API ostream : private detail::buffer<char> { - private: - file file_; - - ostream(cstring_view path, const detail::ostream_params& params); - - static void grow(buffer<char>& buf, size_t); - - public: - ostream(ostream&& other) noexcept; - ~ostream(); - - operator writer() { - detail::buffer<char>& buf = *this; - return buf; - } - - inline void flush() { - if (size() == 0) return; - file_.write(data(), size() * sizeof(data()[0])); - clear(); - } - - template <typename... T> - friend auto output_file(cstring_view path, T... params) -> ostream; - - inline void close() { - flush(); - file_.close(); - } - - /// 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(appender(*this), fmt.str, vargs<T...>{{args...}}); - } -}; - -/** - * 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 | file::TRUNC` by default) - * - `buffer_size=<integer>`: Output buffer size - * - * **Example**: - * - * auto out = fmt::output_file("guide.txt"); - * out.print("Don't {}", "Panic"); - */ -template <typename... T> -inline auto output_file(cstring_view path, T... params) -> ostream { - return {path, detail::ostream_params(params...)}; -} -#endif // FMT_USE_FCNTL - -FMT_END_EXPORT -FMT_END_NAMESPACE - -#endif // FMT_OS_H_ diff --git a/vendor/fmt/ostream.h b/vendor/fmt/ostream.h deleted file mode 100644 index 71fd6c887..000000000 --- a/vendor/fmt/ostream.h +++ /dev/null @@ -1,166 +0,0 @@ -// Formatting library for C++ - std::ostream support -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_OSTREAM_H_ -#define FMT_OSTREAM_H_ - -#ifndef FMT_MODULE -# include <fstream> // std::filebuf -#endif - -#ifdef _WIN32 -# ifdef __GLIBCXX__ -# include <ext/stdio_filebuf.h> -# include <ext/stdio_sync_filebuf.h> -# endif -# include <io.h> -#endif - -#include "chrono.h" // formatbuf - -#ifdef _MSVC_STL_UPDATE -# define FMT_MSVC_STL_UPDATE _MSVC_STL_UPDATE -#elif defined(_MSC_VER) && _MSC_VER < 1912 // VS 15.5 -# define FMT_MSVC_STL_UPDATE _MSVC_LANG -#else -# define FMT_MSVC_STL_UPDATE 0 -#endif - -FMT_BEGIN_NAMESPACE -namespace detail { - -// Generate a unique explicit instantion in every translation unit using a tag -// type in an anonymous namespace. -namespace { -struct file_access_tag {}; -} // namespace -template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr> -class file_access { - friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } -}; - -#if FMT_MSVC_STL_UPDATE -template class file_access<file_access_tag, std::filebuf, - &std::filebuf::_Myfile>; -auto get_file(std::filebuf&) -> FILE*; -#endif - -// Write the content of buf to os. -// It is a separate function rather than a part of vprint to simplify testing. -template <typename Char> -void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) { - const Char* buf_data = buf.data(); - using unsigned_streamsize = make_unsigned_t<std::streamsize>; - unsigned_streamsize size = buf.size(); - unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>()); - do { - unsigned_streamsize n = size <= max_size ? size : max_size; - os.write(buf_data, static_cast<std::streamsize>(n)); - buf_data += n; - size -= n; - } while (size != 0); -} - -template <typename T> struct streamed_view { - const T& value; -}; -} // namespace detail - -// Formats an object of type T that has an overloaded ostream operator<<. -template <typename Char> -struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> { - void set_debug_format() = delete; - - template <typename T, typename Context> - auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) { - auto buffer = basic_memory_buffer<Char>(); - auto&& formatbuf = detail::formatbuf<std::basic_streambuf<Char>>(buffer); - auto&& output = std::basic_ostream<Char>(&formatbuf); - output.imbue(std::locale::classic()); // The default is always unlocalized. - output << value; - output.exceptions(std::ios_base::failbit | std::ios_base::badbit); - return formatter<basic_string_view<Char>, Char>::format( - {buffer.data(), buffer.size()}, ctx); - } -}; - -using ostream_formatter = basic_ostream_formatter<char>; - -template <typename T, typename Char> -struct formatter<detail::streamed_view<T>, Char> - : basic_ostream_formatter<Char> { - template <typename Context> - auto format(detail::streamed_view<T> view, Context& ctx) const - -> decltype(ctx.out()) { - return basic_ostream_formatter<Char>::format(view.value, ctx); - } -}; - -/** - * Returns a view that formats `value` via an ostream `operator<<`. - * - * **Example**: - * - * fmt::print("Current thread id: {}\n", - * fmt::streamed(std::this_thread::get_id())); - */ -template <typename T> -constexpr auto streamed(const T& value) -> detail::streamed_view<T> { - return {value}; -} - -inline void vprint(std::ostream& os, string_view fmt, format_args args) { - auto buffer = memory_buffer(); - detail::vformat_to(buffer, fmt, args); - FILE* f = nullptr; -#if FMT_MSVC_STL_UPDATE && FMT_USE_RTTI - if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf())) - f = detail::get_file(*buf); -#elif defined(_WIN32) && defined(__GLIBCXX__) && FMT_USE_RTTI - auto* rdbuf = os.rdbuf(); - if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf)) - f = sfbuf->file(); - else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf)) - f = fbuf->file(); -#endif -#ifdef _WIN32 - if (f) { - int fd = _fileno(f); - if (_isatty(fd)) { - os.flush(); - if (detail::write_console(fd, {buffer.data(), buffer.size()})) return; - } - } -#endif - detail::ignore_unused(f); - detail::write_buffer(os, buffer); -} - -/** - * Prints formatted data to the stream `os`. - * - * **Example**: - * - * fmt::print(cerr, "Don't {}!", "panic"); - */ -FMT_EXPORT template <typename... T> -void print(std::ostream& os, format_string<T...> fmt, T&&... args) { - fmt::vargs<T...> vargs = {{args...}}; - if (detail::const_check(detail::use_utf8)) return vprint(os, fmt.str, vargs); - auto buffer = memory_buffer(); - detail::vformat_to(buffer, fmt.str, vargs); - detail::write_buffer(os, buffer); -} - -FMT_EXPORT template <typename... T> -void println(std::ostream& os, format_string<T...> fmt, T&&... args) { - fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...)); -} - -FMT_END_NAMESPACE - -#endif // FMT_OSTREAM_H_ diff --git a/vendor/fmt/printf.h b/vendor/fmt/printf.h deleted file mode 100644 index e72684018..000000000 --- a/vendor/fmt/printf.h +++ /dev/null @@ -1,633 +0,0 @@ -// Formatting library for C++ - legacy printf implementation -// -// Copyright (c) 2012 - 2016, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_PRINTF_H_ -#define FMT_PRINTF_H_ - -#ifndef FMT_MODULE -# include <algorithm> // std::max -# include <limits> // std::numeric_limits -#endif - -#include "format.h" - -FMT_BEGIN_NAMESPACE -FMT_BEGIN_EXPORT - -template <typename T> struct printf_formatter { - printf_formatter() = delete; -}; - -template <typename Char> class basic_printf_context { - private: - basic_appender<Char> out_; - basic_format_args<basic_printf_context> args_; - - static_assert(std::is_same<Char, char>::value || - std::is_same<Char, wchar_t>::value, - "Unsupported code unit type."); - - public: - using char_type = Char; - using parse_context_type = parse_context<Char>; - template <typename T> using formatter_type = printf_formatter<T>; - enum { builtin_types = 1 }; - - /// Constructs a `printf_context` object. References to the arguments are - /// stored in the context object so make sure they have appropriate lifetimes. - basic_printf_context(basic_appender<Char> out, - basic_format_args<basic_printf_context> args) - : out_(out), args_(args) {} - - auto out() -> basic_appender<Char> { return out_; } - void advance_to(basic_appender<Char>) {} - - auto locale() -> detail::locale_ref { return {}; } - - auto arg(int id) const -> basic_format_arg<basic_printf_context> { - return args_.get(id); - } -}; - -namespace detail { - -// 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*>(memchr(first, value, to_unsigned(last - first))); - return out != nullptr; -} - -// Checks if a value fits in int - used to avoid warnings about comparing -// signed and unsigned integers. -template <bool IsSigned> struct int_checker { - template <typename T> static auto fits_in_int(T value) -> bool { - unsigned max = to_unsigned(max_value<int>()); - return value <= max; - } - inline static auto fits_in_int(bool) -> bool { return true; } -}; - -template <> struct int_checker<true> { - template <typename T> static auto fits_in_int(T value) -> bool { - return value >= (std::numeric_limits<int>::min)() && - value <= max_value<int>(); - } - inline static auto fits_in_int(int) -> bool { return true; } -}; - -struct printf_precision_handler { - template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> - auto operator()(T value) -> int { - if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) - report_error("number is too big"); - return (std::max)(static_cast<int>(value), 0); - } - - template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> - auto operator()(T) -> int { - report_error("precision is not integer"); - return 0; - } -}; - -// An argument visitor that returns true iff arg is a zero integer. -struct is_zero_int { - template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> - auto operator()(T value) -> bool { - return value == 0; - } - - template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> - auto operator()(T) -> bool { - return false; - } -}; - -template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {}; - -template <> struct make_unsigned_or_bool<bool> { - using type = bool; -}; - -template <typename T, typename Context> class arg_converter { - private: - using char_type = typename Context::char_type; - - basic_format_arg<Context>& arg_; - char_type type_; - - public: - arg_converter(basic_format_arg<Context>& arg, char_type type) - : arg_(arg), type_(type) {} - - void operator()(bool value) { - if (type_ != 's') operator()<bool>(value); - } - - template <typename U, FMT_ENABLE_IF(std::is_integral<U>::value)> - void operator()(U value) { - bool is_signed = type_ == 'd' || type_ == 'i'; - using target_type = conditional_t<std::is_same<T, void>::value, U, T>; - if (const_check(sizeof(target_type) <= sizeof(int))) { - // Extra casts are used to silence warnings. - using unsigned_type = typename make_unsigned_or_bool<target_type>::type; - if (is_signed) - arg_ = static_cast<int>(static_cast<target_type>(value)); - else - arg_ = static_cast<unsigned>(static_cast<unsigned_type>(value)); - } else { - // glibc's printf doesn't sign extend arguments of smaller types: - // std::printf("%lld", -42); // prints "4294967254" - // but we don't have to do the same because it's a UB. - if (is_signed) - arg_ = static_cast<long long>(value); - else - arg_ = static_cast<typename make_unsigned_or_bool<U>::type>(value); - } - } - - template <typename U, FMT_ENABLE_IF(!std::is_integral<U>::value)> - void operator()(U) {} // No conversion needed for non-integral types. -}; - -// Converts an integer argument to T for printf, if T is an integral type. -// If T is void, the argument is converted to corresponding signed or unsigned -// type depending on the type specifier: 'd' and 'i' - signed, other - -// unsigned). -template <typename T, typename Context, typename Char> -void convert_arg(basic_format_arg<Context>& arg, Char type) { - arg.visit(arg_converter<T, Context>(arg, type)); -} - -// Converts an integer argument to char for printf. -template <typename Context> class char_converter { - private: - basic_format_arg<Context>& arg_; - - public: - explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {} - - template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> - void operator()(T value) { - arg_ = static_cast<typename Context::char_type>(value); - } - - template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> - void operator()(T) {} // No conversion needed for non-integral types. -}; - -// An argument visitor that return a pointer to a C string if argument is a -// string or null otherwise. -template <typename Char> struct get_cstring { - template <typename T> auto operator()(T) -> const Char* { return nullptr; } - auto operator()(const Char* s) -> const Char* { return s; } -}; - -// Checks if an argument is a valid printf width specifier and sets -// left alignment if it is negative. -class printf_width_handler { - private: - format_specs& specs_; - - public: - inline explicit printf_width_handler(format_specs& specs) : specs_(specs) {} - - template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> - auto operator()(T value) -> unsigned { - auto width = static_cast<uint32_or_64_or_128_t<T>>(value); - if (detail::is_negative(value)) { - specs_.set_align(align::left); - width = 0 - width; - } - unsigned int_max = to_unsigned(max_value<int>()); - if (width > int_max) report_error("number is too big"); - return static_cast<unsigned>(width); - } - - template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> - auto operator()(T) -> unsigned { - report_error("width is not integer"); - return 0; - } -}; - -// Workaround for a bug with the XL compiler when initializing -// printf_arg_formatter's base class. -template <typename Char> -auto make_arg_formatter(basic_appender<Char> iter, format_specs& s) - -> arg_formatter<Char> { - return {iter, s, locale_ref()}; -} - -// The `printf` argument formatter. -template <typename Char> -class printf_arg_formatter : public arg_formatter<Char> { - private: - using base = arg_formatter<Char>; - using context_type = basic_printf_context<Char>; - - context_type& context_; - - void write_null_pointer(bool is_string = false) { - auto s = this->specs; - s.set_type(presentation_type::none); - write_bytes<Char>(this->out, is_string ? "(null)" : "(nil)", s); - } - - template <typename T> void write(T value) { - detail::write<Char>(this->out, value, this->specs, this->locale); - } - - public: - printf_arg_formatter(basic_appender<Char> iter, format_specs& s, - context_type& ctx) - : base(make_arg_formatter(iter, s)), context_(ctx) {} - - void operator()(monostate value) { write(value); } - - template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)> - void 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) { - write(value); - return; - } - format_specs s = this->specs; - if (s.type() != presentation_type::none && - s.type() != presentation_type::chr) { - return (*this)(static_cast<int>(value)); - } - s.set_sign(sign::none); - s.clear_alt(); - s.set_fill(' '); // Ignore '0' flag for char types. - // align::numeric needs to be overwritten here since the '0' flag is - // ignored for non-numeric types - if (s.align() == align::none || s.align() == align::numeric) - s.set_align(align::right); - detail::write<Char>(this->out, static_cast<Char>(value), s); - } - - template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> - void operator()(T value) { - write(value); - } - - void operator()(const char* value) { - if (value) - write(value); - else - write_null_pointer(this->specs.type() != presentation_type::pointer); - } - - void operator()(const wchar_t* value) { - if (value) - write(value); - else - write_null_pointer(this->specs.type() != presentation_type::pointer); - } - - void operator()(basic_string_view<Char> value) { write(value); } - - void operator()(const void* value) { - if (value) - write(value); - else - write_null_pointer(); - } - - void operator()(typename basic_format_arg<context_type>::handle handle) { - auto parse_ctx = parse_context<Char>({}); - handle.format(parse_ctx, context_); - } -}; - -template <typename Char> -void parse_flags(format_specs& specs, const Char*& it, const Char* end) { - for (; it != end; ++it) { - switch (*it) { - case '-': specs.set_align(align::left); break; - case '+': specs.set_sign(sign::plus); break; - case '0': specs.set_fill('0'); break; - case ' ': - if (specs.sign() != sign::plus) specs.set_sign(sign::space); - break; - case '#': specs.set_alt(); break; - default: return; - } - } -} - -template <typename Char, typename GetArg> -auto parse_header(const Char*& it, const Char* end, format_specs& specs, - GetArg get_arg) -> int { - int arg_index = -1; - Char c = *it; - if (c >= '0' && c <= '9') { - // Parse an argument index (if followed by '$') or a width possibly - // preceded with '0' flag(s). - int value = parse_nonnegative_int(it, end, -1); - if (it != end && *it == '$') { // value is an argument index - ++it; - arg_index = value != -1 ? value : max_value<int>(); - } else { - if (c == '0') specs.set_fill('0'); - if (value != 0) { - // Nonzero value means that we parsed width and don't need to - // parse it or flags again, so return now. - if (value == -1) report_error("number is too big"); - specs.width = value; - return arg_index; - } - } - } - parse_flags(specs, it, end); - // Parse width. - if (it != end) { - if (*it >= '0' && *it <= '9') { - specs.width = parse_nonnegative_int(it, end, -1); - if (specs.width == -1) report_error("number is too big"); - } else if (*it == '*') { - ++it; - specs.width = static_cast<int>( - get_arg(-1).visit(detail::printf_width_handler(specs))); - } - } - return arg_index; -} - -inline auto parse_printf_presentation_type(char c, type t, bool& upper) - -> presentation_type { - using pt = presentation_type; - constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; - switch (c) { - case 'd': return in(t, integral_set) ? pt::dec : pt::none; - case 'o': return in(t, integral_set) ? pt::oct : pt::none; - case 'X': upper = true; FMT_FALLTHROUGH; - case 'x': return in(t, integral_set) ? pt::hex : pt::none; - case 'E': upper = true; FMT_FALLTHROUGH; - case 'e': return in(t, float_set) ? pt::exp : pt::none; - case 'F': upper = true; FMT_FALLTHROUGH; - case 'f': return in(t, float_set) ? pt::fixed : pt::none; - case 'G': upper = true; FMT_FALLTHROUGH; - case 'g': return in(t, float_set) ? pt::general : pt::none; - case 'A': upper = true; FMT_FALLTHROUGH; - case 'a': return in(t, float_set) ? pt::hexfloat : pt::none; - case 'c': return in(t, integral_set) ? pt::chr : pt::none; - case 's': return in(t, string_set | cstring_set) ? pt::string : pt::none; - case 'p': return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none; - default: return pt::none; - } -} - -template <typename Char, typename Context> -void vprintf(buffer<Char>& buf, basic_string_view<Char> format, - basic_format_args<Context> args) { - using iterator = basic_appender<Char>; - auto out = iterator(buf); - auto context = basic_printf_context<Char>(out, args); - auto parse_ctx = 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) { - if (!find<false, Char>(it, end, '%', it)) { - it = end; // find leaves it == nullptr if it doesn't find '%'. - break; - } - Char c = *it++; - if (it != end && *it == c) { - write(out, basic_string_view<Char>(start, to_unsigned(it - start))); - start = ++it; - continue; - } - write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start))); - - auto specs = format_specs(); - specs.set_align(align::right); - - // Parse argument index, flags and width. - int arg_index = parse_header(it, end, specs, get_arg); - if (arg_index == 0) report_error("argument not found"); - - // Parse precision. - if (it != end && *it == '.') { - ++it; - c = it != end ? *it : 0; - if ('0' <= c && c <= '9') { - specs.precision = parse_nonnegative_int(it, end, 0); - } else if (c == '*') { - ++it; - specs.precision = - static_cast<int>(get_arg(-1).visit(printf_precision_handler())); - } else { - specs.precision = 0; - } - } - - 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 && is_integral_type(arg.type())) { - // Ignore '0' for non-numeric types or if '-' present. - specs.set_fill(' '); - } - if (specs.precision >= 0 && arg.type() == type::cstring_type) { - auto str = arg.visit(get_cstring<Char>()); - auto str_end = str + specs.precision; - auto nul = std::find(str, str_end, Char()); - auto sv = basic_string_view<Char>( - str, to_unsigned(nul != str_end ? nul - str : specs.precision)); - arg = sv; - } - if (specs.alt() && arg.visit(is_zero_int())) specs.clear_alt(); - if (specs.fill_unit<Char>() == '0') { - if (is_arithmetic_type(arg.type()) && specs.align() != align::left) { - specs.set_align(align::numeric); - } else { - // Ignore '0' flag for non-numeric types or if '-' flag is also present. - specs.set_fill(' '); - } - } - - // Parse length and convert the argument to the required type. - c = it != end ? *it++ : 0; - Char t = it != end ? *it : 0; - switch (c) { - case 'h': - if (t == 'h') { - ++it; - t = it != end ? *it : 0; - convert_arg<signed char>(arg, t); - } else { - convert_arg<short>(arg, t); - } - break; - case 'l': - if (t == 'l') { - ++it; - t = it != end ? *it : 0; - convert_arg<long long>(arg, t); - } else { - convert_arg<long>(arg, t); - } - break; - case 'j': convert_arg<intmax_t>(arg, t); break; - case 'z': convert_arg<size_t>(arg, t); break; - case 't': convert_arg<std::ptrdiff_t>(arg, t); break; - case 'L': - // printf produces garbage when 'L' is omitted for long double, no - // need to do the same. - break; - default: --it; convert_arg<void>(arg, c); - } - - // Parse type. - if (it == end) report_error("invalid format string"); - char type = static_cast<char>(*it++); - if (is_integral_type(arg.type())) { - // Normalize type. - switch (type) { - case 'i': - case 'u': type = 'd'; break; - case 'c': - arg.visit(char_converter<basic_printf_context<Char>>(arg)); - break; - } - } - bool upper = false; - specs.set_type(parse_printf_presentation_type(type, arg.type(), upper)); - if (specs.type() == presentation_type::none) - report_error("invalid format specifier"); - if (upper) specs.set_upper(); - - start = it; - - // Format argument. - arg.visit(printf_arg_formatter<Char>(out, specs, context)); - } - write(out, basic_string_view<Char>(start, to_unsigned(it - start))); -} -} // namespace detail - -using printf_context = basic_printf_context<char>; -using wprintf_context = basic_printf_context<wchar_t>; - -using printf_args = basic_format_args<printf_context>; -using wprintf_args = basic_format_args<wprintf_context>; - -/// Constructs an `format_arg_store` object that contains references to -/// arguments and can be implicitly converted to `printf_args`. -template <typename Char = char, typename... T> -inline auto make_printf_args(T&... args) - -> decltype(fmt::make_format_args<basic_printf_context<Char>>(args...)) { - return fmt::make_format_args<basic_printf_context<Char>>(args...); -} - -template <typename Char> struct vprintf_args { - using type = basic_format_args<basic_printf_context<Char>>; -}; - -template <typename Char> -inline auto vsprintf(basic_string_view<Char> fmt, - typename vprintf_args<Char>::type args) - -> std::basic_string<Char> { - auto buf = basic_memory_buffer<Char>(); - detail::vprintf(buf, fmt, args); - return {buf.data(), buf.size()}; -} - -/** - * Formats `args` according to specifications in `fmt` and returns the result - * as as string. - * - * **Example**: - * - * std::string message = fmt::sprintf("The answer is %d", 42); - */ -template <typename S, typename... T, typename Char = detail::char_t<S>> -inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> { - return vsprintf(detail::to_string_view(fmt), - fmt::make_format_args<basic_printf_context<Char>>(args...)); -} - -template <typename Char> -inline auto vfprintf(std::FILE* f, basic_string_view<Char> fmt, - typename vprintf_args<Char>::type args) -> int { - auto buf = basic_memory_buffer<Char>(); - detail::vprintf(buf, fmt, args); - size_t size = buf.size(); - return std::fwrite(buf.data(), sizeof(Char), size, f) < size - ? -1 - : static_cast<int>(size); -} - -/** - * Formats `args` according to specifications in `fmt` and writes the output - * to `f`. - * - * **Example**: - * - * fmt::fprintf(stderr, "Don't %s!", "panic"); - */ -template <typename S, typename... T, typename Char = detail::char_t<S>> -inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int { - return vfprintf(f, detail::to_string_view(fmt), - make_printf_args<Char>(args...)); -} - -template <typename Char> -FMT_DEPRECATED inline auto vprintf(basic_string_view<Char> fmt, - typename vprintf_args<Char>::type args) - -> int { - return vfprintf(stdout, fmt, args); -} - -/** - * Formats `args` according to specifications in `fmt` and writes the output - * to `stdout`. - * - * **Example**: - * - * fmt::printf("Elapsed time: %.2f seconds", 1.23); - */ -template <typename... T> -inline auto printf(string_view fmt, const T&... args) -> int { - return vfprintf(stdout, fmt, make_printf_args(args...)); -} -template <typename... T> -FMT_DEPRECATED inline auto printf(basic_string_view<wchar_t> fmt, - const T&... args) -> int { - return vfprintf(stdout, fmt, make_printf_args<wchar_t>(args...)); -} - -FMT_END_EXPORT -FMT_END_NAMESPACE - -#endif // FMT_PRINTF_H_ diff --git a/vendor/fmt/ranges.h b/vendor/fmt/ranges.h deleted file mode 100644 index 77d645f8e..000000000 --- a/vendor/fmt/ranges.h +++ /dev/null @@ -1,850 +0,0 @@ -// Formatting library for C++ - range and tuple support -// -// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_RANGES_H_ -#define FMT_RANGES_H_ - -#ifndef FMT_MODULE -# include <initializer_list> -# include <iterator> -# include <string> -# include <tuple> -# include <type_traits> -# include <utility> -#endif - -#include "format.h" - -FMT_BEGIN_NAMESPACE - -FMT_EXPORT -enum class range_format { disabled, map, set, sequence, string, debug_string }; - -namespace detail { - -template <typename T> class is_map { - template <typename U> static auto check(U*) -> typename U::mapped_type; - template <typename> static void check(...); - - public: - static constexpr const bool value = - !std::is_void<decltype(check<T>(nullptr))>::value; -}; - -template <typename T> class is_set { - template <typename U> static auto check(U*) -> typename U::key_type; - template <typename> static void check(...); - - public: - static constexpr const bool value = - !std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value; -}; - -// 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 overloads. -template <typename T> -auto range_begin(T&& rng) -> decltype(static_cast<T&&>(rng).begin()) { - return static_cast<T&&>(rng).begin(); -} -template <typename T> -auto range_end(T&& rng) -> decltype(static_cast<T&&>(rng).end()) { - return static_cast<T&&>(rng).end(); -} - -// ADL overloads. Only participate 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 has_const_begin_end< - T, void_t<decltype(*detail::range_begin( - std::declval<const remove_cvref_t<T>&>())), - decltype(detail::range_end( - 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_end(std::declval<T&>())), - // the extra int here is because older versions of MSVC don't - // SFINAE properly unless there are distinct types - int>> : std::true_type {}; - -template <typename T, typename _ = void> struct is_range_ : std::false_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)> {}; - -// tuple_size and tuple_element check. -template <typename T> class is_tuple_like_ { - template <typename U, typename V = typename std::remove_cv<U>::type> - static auto check(U* p) -> decltype(std::tuple_size<V>::value, 0); - template <typename> static void check(...); - - public: - static constexpr const bool value = - !std::is_void<decltype(check<T>(nullptr))>::value; -}; - -// Check for integer_sequence -#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900 -template <typename T, T... N> -using integer_sequence = std::integer_sequence<T, N...>; -template <size_t... N> using index_sequence = std::index_sequence<N...>; -template <size_t N> using make_index_sequence = std::make_index_sequence<N>; -#else -template <typename T, T... N> struct integer_sequence { - using value_type = T; - - static FMT_CONSTEXPR auto size() -> size_t { return sizeof...(N); } -}; - -template <size_t... N> using index_sequence = integer_sequence<size_t, N...>; - -template <typename T, size_t N, T... Ns> -struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {}; -template <typename T, T... Ns> -struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {}; - -template <size_t N> -using make_index_sequence = make_integer_sequence<size_t, N>; -#endif - -template <typename T> -using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>; - -template <typename T, typename C, bool = is_tuple_like_<T>::value> -class is_tuple_formattable_ { - public: - static constexpr const bool value = false; -}; -template <typename T, typename C> class is_tuple_formattable_<T, C, true> { - template <size_t... Is> - static auto all_true(index_sequence<Is...>, - integer_sequence<bool, (Is >= 0)...>) -> std::true_type; - static auto all_true(...) -> std::false_type; - - template <size_t... Is> - static auto check(index_sequence<Is...>) -> decltype(all_true( - index_sequence<Is...>{}, - integer_sequence<bool, - (is_formattable<typename std::tuple_element<Is, T>::type, - C>::value)...>{})); - - public: - static constexpr const bool value = - decltype(check(tuple_index_sequence<T>{}))::value; -}; - -template <typename Tuple, typename F, size_t... Is> -FMT_CONSTEXPR void for_each(index_sequence<Is...>, Tuple&& t, F&& f) { - using std::get; - // Using a free function get<Is>(Tuple) now. - const int unused[] = {0, ((void)f(get<Is>(t)), 0)...}; - ignore_unused(unused); -} - -template <typename Tuple, typename F> -FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) { - for_each(tuple_index_sequence<remove_cvref_t<Tuple>>(), - std::forward<Tuple>(t), std::forward<F>(f)); -} - -template <typename Tuple1, typename Tuple2, typename F, size_t... Is> -void for_each2(index_sequence<Is...>, Tuple1&& t1, Tuple2&& t2, F&& f) { - using std::get; - const int unused[] = {0, ((void)f(get<Is>(t1), get<Is>(t2)), 0)...}; - ignore_unused(unused); -} - -template <typename Tuple1, typename Tuple2, typename F> -void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) { - for_each2(tuple_index_sequence<remove_cvref_t<Tuple1>>(), - std::forward<Tuple1>(t1), std::forward<Tuple2>(t2), - std::forward<F>(f)); -} - -namespace tuple { -// Workaround a bug in MSVC 2019 (v140). -template <typename Char, typename... T> -using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>; - -using std::get; -template <typename Tuple, typename Char, std::size_t... Is> -auto get_formatters(index_sequence<Is...>) - -> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>; -} // namespace tuple - -#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920 -// Older MSVC doesn't get the reference type correctly for arrays. -template <typename R> struct range_reference_type_impl { - using type = decltype(*detail::range_begin(std::declval<R&>())); -}; - -template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> { - using type = T&; -}; - -template <typename T> -using range_reference_type = typename range_reference_type_impl<T>::type; -#else -template <typename Range> -using range_reference_type = - decltype(*detail::range_begin(std::declval<Range&>())); -#endif - -// We don't use the Range's value_type for anything, but we do need the Range's -// reference type, with cv-ref stripped. -template <typename Range> -using uncvref_type = remove_cvref_t<range_reference_type<Range>>; - -template <typename Formatter> -FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set) - -> decltype(f.set_debug_format(set)) { - f.set_debug_format(set); -} -template <typename Formatter> -FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {} - -template <typename T> -struct range_format_kind_ - : std::integral_constant<range_format, - std::is_same<uncvref_type<T>, T>::value - ? range_format::disabled - : is_map<T>::value ? range_format::map - : is_set<T>::value ? range_format::set - : range_format::sequence> {}; - -template <range_format K> -using range_format_constant = std::integral_constant<range_format, K>; - -// These are not generic lambdas for compatibility with C++11. -template <typename Char> struct parse_empty_specs { - template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) { - f.parse(ctx); - detail::maybe_set_debug_format(f, true); - } - parse_context<Char>& ctx; -}; -template <typename FormatContext> struct format_tuple_element { - using char_type = typename FormatContext::char_type; - - template <typename T> - void operator()(const formatter<T, char_type>& f, const T& v) { - if (i > 0) ctx.advance_to(detail::copy<char_type>(separator, ctx.out())); - ctx.advance_to(f.format(v, ctx)); - ++i; - } - - int i; - FormatContext& ctx; - basic_string_view<char_type> separator; -}; - -} // namespace detail - -template <typename T> struct is_tuple_like { - static constexpr const bool value = - detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value; -}; - -template <typename T, typename C> struct is_tuple_formattable { - static constexpr const bool value = - detail::is_tuple_formattable_<T, C>::value; -}; - -template <typename Tuple, typename Char> -struct formatter<Tuple, Char, - enable_if_t<fmt::is_tuple_like<Tuple>::value && - fmt::is_tuple_formattable<Tuple, Char>::value>> { - private: - decltype(detail::tuple::get_formatters<Tuple, Char>( - detail::tuple_index_sequence<Tuple>())) formatters_; - - basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{}; - basic_string_view<Char> opening_bracket_ = - detail::string_literal<Char, '('>{}; - basic_string_view<Char> closing_bracket_ = - detail::string_literal<Char, ')'>{}; - - public: - FMT_CONSTEXPR formatter() {} - - FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) { - separator_ = sep; - } - - FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open, - basic_string_view<Char> close) { - opening_bracket_ = open; - closing_bracket_ = close; - } - - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - auto it = ctx.begin(); - auto end = ctx.end(); - if (it != end && detail::to_ascii(*it) == 'n') { - ++it; - set_brackets({}, {}); - set_separator({}); - } - if (it != end && *it != '}') report_error("invalid format specifier"); - ctx.advance_to(it); - detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx}); - return it; - } - - template <typename FormatContext> - auto format(const Tuple& value, FormatContext& ctx) const - -> decltype(ctx.out()) { - ctx.advance_to(detail::copy<Char>(opening_bracket_, ctx.out())); - detail::for_each2( - formatters_, value, - detail::format_tuple_element<FormatContext>{0, ctx, separator_}); - return detail::copy<Char>(closing_bracket_, ctx.out()); - } -}; - -template <typename T, typename Char> struct is_range { - static constexpr const bool value = - detail::is_range_<T>::value && !detail::has_to_string_view<T>::value; -}; - -namespace detail { - -template <typename Char, typename Element> -using range_formatter_type = formatter<remove_cvref_t<Element>, Char>; - -template <typename R> -using maybe_const_range = - conditional_t<has_const_begin_end<R>::value, const R, R>; - -template <typename R, typename Char> -struct is_formattable_delayed - : is_formattable<uncvref_type<maybe_const_range<R>>, Char> {}; -} // namespace detail - -template <typename...> struct conjunction : std::true_type {}; -template <typename P> struct conjunction<P> : P {}; -template <typename P1, typename... Pn> -struct conjunction<P1, Pn...> - : conditional_t<bool(P1::value), conjunction<Pn...>, P1> {}; - -template <typename T, typename Char, typename Enable = void> -struct range_formatter; - -template <typename T, typename Char> -struct range_formatter< - T, Char, - enable_if_t<conjunction<std::is_same<T, remove_cvref_t<T>>, - is_formattable<T, Char>>::value>> { - private: - detail::range_formatter_type<Char, T> underlying_; - basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{}; - basic_string_view<Char> opening_bracket_ = - detail::string_literal<Char, '['>{}; - basic_string_view<Char> closing_bracket_ = - detail::string_literal<Char, ']'>{}; - bool is_debug = false; - - template <typename Output, typename It, typename Sentinel, typename U = T, - FMT_ENABLE_IF(std::is_same<U, Char>::value)> - auto write_debug_string(Output& out, It it, Sentinel end) const -> Output { - auto buf = basic_memory_buffer<Char>(); - for (; it != end; ++it) buf.push_back(*it); - auto specs = format_specs(); - specs.set_type(presentation_type::debug); - return detail::write<Char>( - out, basic_string_view<Char>(buf.data(), buf.size()), specs); - } - - template <typename Output, typename It, typename Sentinel, typename U = T, - FMT_ENABLE_IF(!std::is_same<U, Char>::value)> - auto write_debug_string(Output& out, It, Sentinel) const -> Output { - return out; - } - - public: - FMT_CONSTEXPR range_formatter() {} - - FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& { - return underlying_; - } - - FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) { - separator_ = sep; - } - - FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open, - basic_string_view<Char> close) { - opening_bracket_ = open; - closing_bracket_ = close; - } - - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - auto it = ctx.begin(); - auto end = ctx.end(); - detail::maybe_set_debug_format(underlying_, true); - if (it == end) return underlying_.parse(ctx); - - switch (detail::to_ascii(*it)) { - case 'n': - set_brackets({}, {}); - ++it; - break; - case '?': - is_debug = true; - set_brackets({}, {}); - ++it; - if (it == end || *it != 's') report_error("invalid format specifier"); - FMT_FALLTHROUGH; - case 's': - if (!std::is_same<T, Char>::value) - report_error("invalid format specifier"); - if (!is_debug) { - set_brackets(detail::string_literal<Char, '"'>{}, - detail::string_literal<Char, '"'>{}); - set_separator({}); - detail::maybe_set_debug_format(underlying_, false); - } - ++it; - return it; - } - - if (it != end && *it != '}') { - if (*it != ':') report_error("invalid format specifier"); - detail::maybe_set_debug_format(underlying_, false); - ++it; - } - - ctx.advance_to(it); - return underlying_.parse(ctx); - } - - template <typename R, typename FormatContext> - auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) { - auto out = ctx.out(); - auto it = detail::range_begin(range); - auto end = detail::range_end(range); - if (is_debug) return write_debug_string(out, std::move(it), end); - - out = detail::copy<Char>(opening_bracket_, out); - int i = 0; - for (; it != end; ++it) { - if (i > 0) out = detail::copy<Char>(separator_, out); - ctx.advance_to(out); - auto&& item = *it; // Need an lvalue - out = underlying_.format(item, ctx); - ++i; - } - out = detail::copy<Char>(closing_bracket_, out); - return out; - } -}; - -FMT_EXPORT -template <typename T, typename Char, typename Enable = void> -struct range_format_kind - : conditional_t< - is_range<T, Char>::value, detail::range_format_kind_<T>, - std::integral_constant<range_format, range_format::disabled>> {}; - -template <typename R, typename Char> -struct formatter< - R, Char, - enable_if_t<conjunction< - bool_constant< - range_format_kind<R, Char>::value != range_format::disabled && - range_format_kind<R, Char>::value != range_format::map && - range_format_kind<R, Char>::value != range_format::string && - range_format_kind<R, Char>::value != range_format::debug_string>, - detail::is_formattable_delayed<R, Char>>::value>> { - private: - using range_type = detail::maybe_const_range<R>; - range_formatter<detail::uncvref_type<range_type>, Char> range_formatter_; - - public: - using nonlocking = void; - - FMT_CONSTEXPR formatter() { - if (detail::const_check(range_format_kind<R, Char>::value != - range_format::set)) - return; - range_formatter_.set_brackets(detail::string_literal<Char, '{'>{}, - detail::string_literal<Char, '}'>{}); - } - - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - return range_formatter_.parse(ctx); - } - - template <typename FormatContext> - auto format(range_type& range, FormatContext& ctx) const - -> decltype(ctx.out()) { - return range_formatter_.format(range, ctx); - } -}; - -// A map formatter. -template <typename R, typename Char> -struct formatter< - R, Char, - enable_if_t<conjunction< - bool_constant<range_format_kind<R, Char>::value == range_format::map>, - detail::is_formattable_delayed<R, Char>>::value>> { - private: - using map_type = detail::maybe_const_range<R>; - using element_type = detail::uncvref_type<map_type>; - - decltype(detail::tuple::get_formatters<element_type, Char>( - detail::tuple_index_sequence<element_type>())) formatters_; - bool no_delimiters_ = false; - - public: - FMT_CONSTEXPR formatter() {} - - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - auto it = ctx.begin(); - auto end = ctx.end(); - if (it != end) { - if (detail::to_ascii(*it) == 'n') { - no_delimiters_ = true; - ++it; - } - if (it != end && *it != '}') { - if (*it != ':') report_error("invalid format specifier"); - ++it; - } - ctx.advance_to(it); - } - detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx}); - return it; - } - - template <typename FormatContext> - auto format(map_type& map, FormatContext& ctx) const -> decltype(ctx.out()) { - auto out = ctx.out(); - basic_string_view<Char> open = detail::string_literal<Char, '{'>{}; - if (!no_delimiters_) out = detail::copy<Char>(open, out); - int i = 0; - basic_string_view<Char> sep = detail::string_literal<Char, ',', ' '>{}; - for (auto&& value : map) { - if (i > 0) out = detail::copy<Char>(sep, out); - ctx.advance_to(out); - detail::for_each2(formatters_, value, - detail::format_tuple_element<FormatContext>{ - 0, ctx, detail::string_literal<Char, ':', ' '>{}}); - ++i; - } - basic_string_view<Char> close = detail::string_literal<Char, '}'>{}; - if (!no_delimiters_) out = detail::copy<Char>(close, out); - return out; - } -}; - -// A (debug_)string formatter. -template <typename R, typename Char> -struct formatter< - R, Char, - enable_if_t<range_format_kind<R, Char>::value == range_format::string || - range_format_kind<R, Char>::value == - range_format::debug_string>> { - private: - using range_type = detail::maybe_const_range<R>; - using string_type = - conditional_t<std::is_constructible< - detail::std_string_view<Char>, - decltype(detail::range_begin(std::declval<R>())), - decltype(detail::range_end(std::declval<R>()))>::value, - detail::std_string_view<Char>, std::basic_string<Char>>; - - formatter<string_type, Char> underlying_; - - public: - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - return underlying_.parse(ctx); - } - - template <typename FormatContext> - auto format(range_type& range, FormatContext& ctx) const - -> decltype(ctx.out()) { - auto out = ctx.out(); - if (detail::const_check(range_format_kind<R, Char>::value == - range_format::debug_string)) - *out++ = '"'; - out = underlying_.format( - string_type{detail::range_begin(range), detail::range_end(range)}, ctx); - if (detail::const_check(range_format_kind<R, Char>::value == - range_format::debug_string)) - *out++ = '"'; - return out; - } -}; - -template <typename It, typename Sentinel, typename Char = char> -struct join_view : detail::view { - It begin; - Sentinel end; - basic_string_view<Char> sep; - - join_view(It b, Sentinel e, basic_string_view<Char> s) - : begin(std::move(b)), end(e), sep(s) {} -}; - -template <typename It, typename Sentinel, typename Char> -struct formatter<join_view<It, Sentinel, Char>, Char> { - private: - using value_type = -#ifdef __cpp_lib_ranges - std::iter_value_t<It>; -#else - typename std::iterator_traits<It>::value_type; -#endif - formatter<remove_cvref_t<value_type>, Char> value_formatter_; - - using view = conditional_t<std::is_copy_constructible<It>::value, - const join_view<It, Sentinel, Char>, - join_view<It, Sentinel, Char>>; - - public: - using nonlocking = void; - - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - return value_formatter_.parse(ctx); - } - - template <typename FormatContext> - auto format(view& value, FormatContext& ctx) const -> decltype(ctx.out()) { - using iter = - conditional_t<std::is_copy_constructible<view>::value, It, It&>; - iter it = value.begin; - auto out = ctx.out(); - if (it == value.end) return out; - out = value_formatter_.format(*it, ctx); - ++it; - while (it != value.end) { - out = detail::copy<Char>(value.sep.begin(), value.sep.end(), out); - ctx.advance_to(out); - out = value_formatter_.format(*it, ctx); - ++it; - } - return out; - } -}; - -template <typename Char, typename Tuple> struct tuple_join_view : detail::view { - const Tuple& tuple; - basic_string_view<Char> sep; - - tuple_join_view(const Tuple& t, basic_string_view<Char> s) - : tuple(t), sep{s} {} -}; - -// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers -// support in tuple_join. It is disabled by default because of issues with -// the dynamic width and precision. -#ifndef FMT_TUPLE_JOIN_SPECIFIERS -# define FMT_TUPLE_JOIN_SPECIFIERS 0 -#endif - -template <typename Char, typename Tuple> -struct formatter<tuple_join_view<Char, Tuple>, Char, - enable_if_t<is_tuple_like<Tuple>::value>> { - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - return do_parse(ctx, std::tuple_size<Tuple>()); - } - - template <typename FormatContext> - auto format(const tuple_join_view<Char, Tuple>& value, - FormatContext& ctx) const -> typename FormatContext::iterator { - return do_format(value, ctx, std::tuple_size<Tuple>()); - } - - private: - decltype(detail::tuple::get_formatters<Tuple, Char>( - detail::tuple_index_sequence<Tuple>())) formatters_; - - FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx, - std::integral_constant<size_t, 0>) - -> const Char* { - return ctx.begin(); - } - - template <size_t N> - FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx, - std::integral_constant<size_t, N>) - -> const Char* { - auto end = ctx.begin(); -#if FMT_TUPLE_JOIN_SPECIFIERS - end = std::get<std::tuple_size<Tuple>::value - N>(formatters_).parse(ctx); - if (N > 1) { - auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>()); - if (end != end1) - report_error("incompatible format specs for tuple elements"); - } -#endif - return end; - } - - template <typename FormatContext> - auto do_format(const tuple_join_view<Char, Tuple>&, FormatContext& ctx, - std::integral_constant<size_t, 0>) const -> - typename FormatContext::iterator { - return ctx.out(); - } - - template <typename FormatContext, size_t N> - auto do_format(const tuple_join_view<Char, Tuple>& value, FormatContext& ctx, - std::integral_constant<size_t, N>) const -> - typename FormatContext::iterator { - using std::get; - auto out = - std::get<std::tuple_size<Tuple>::value - N>(formatters_) - .format(get<std::tuple_size<Tuple>::value - N>(value.tuple), ctx); - if (N <= 1) return out; - out = detail::copy<Char>(value.sep, out); - ctx.advance_to(out); - return do_format(value, ctx, std::integral_constant<size_t, N - 1>()); - } -}; - -namespace detail { -// Check if T has an interface like a container adaptor (e.g. std::stack, -// std::queue, std::priority_queue). -template <typename T> class is_container_adaptor_like { - template <typename U> static auto check(U* p) -> typename U::container_type; - template <typename> static void check(...); - - public: - static constexpr const bool value = - !std::is_void<decltype(check<T>(nullptr))>::value; -}; - -template <typename Container> struct all { - const Container& c; - auto begin() const -> typename Container::const_iterator { return c.begin(); } - auto end() const -> typename Container::const_iterator { return c.end(); } -}; -} // namespace detail - -template <typename T, typename Char> -struct formatter< - T, Char, - enable_if_t<conjunction<detail::is_container_adaptor_like<T>, - bool_constant<range_format_kind<T, Char>::value == - range_format::disabled>>::value>> - : formatter<detail::all<typename T::container_type>, Char> { - using all = detail::all<typename T::container_type>; - template <typename FormatContext> - auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) { - struct getter : T { - static auto get(const T& t) -> all { - return {t.*(&getter::c)}; // Access c through the derived class. - } - }; - return formatter<all>::format(getter::get(t), ctx); - } -}; - -FMT_BEGIN_EXPORT - -/// Returns a view that formats the iterator range `[begin, end)` with elements -/// separated by `sep`. -template <typename It, typename Sentinel> -auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> { - return {std::move(begin), end, sep}; -} - -/** - * Returns a view that formats `range` with elements separated by `sep`. - * - * **Example**: - * - * auto v = std::vector<int>{1, 2, 3}; - * fmt::print("{}", fmt::join(v, ", ")); - * // Output: 1, 2, 3 - * - * `fmt::join` applies passed format specifiers to the range elements: - * - * fmt::print("{:02}", fmt::join(v, ", ")); - * // Output: 01, 02, 03 - */ -template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)> -auto join(Range&& r, string_view sep) - -> join_view<decltype(detail::range_begin(r)), - decltype(detail::range_end(r))> { - return {detail::range_begin(r), detail::range_end(r), sep}; -} - -/** - * Returns an object that formats `std::tuple` with elements separated by `sep`. - * - * **Example**: - * - * auto t = std::tuple<int, char>{1, 'a'}; - * fmt::print("{}", fmt::join(t, ", ")); - * // Output: 1, a - */ -template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)> -FMT_CONSTEXPR auto join(const Tuple& tuple, string_view sep) - -> tuple_join_view<char, Tuple> { - return {tuple, sep}; -} - -/** - * Returns an object that formats `std::initializer_list` with elements - * separated by `sep`. - * - * **Example**: - * - * fmt::print("{}", fmt::join({1, 2, 3}, ", ")); - * // Output: "1, 2, 3" - */ -template <typename T> -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_END_EXPORT -FMT_END_NAMESPACE - -#endif // FMT_RANGES_H_ diff --git a/vendor/fmt/std.h b/vendor/fmt/std.h deleted file mode 100644 index 54eb2c2a7..000000000 --- a/vendor/fmt/std.h +++ /dev/null @@ -1,726 +0,0 @@ -// Formatting library for C++ - formatters for standard library types -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_STD_H_ -#define FMT_STD_H_ - -#include "format.h" -#include "ostream.h" - -#ifndef FMT_MODULE -# include <atomic> -# include <bitset> -# include <complex> -# include <cstdlib> -# include <exception> -# include <functional> -# include <memory> -# include <thread> -# include <type_traits> -# include <typeinfo> -# include <utility> -# include <vector> - -// Check FMT_CPLUSPLUS to suppress a bogus warning in MSVC. -# if FMT_CPLUSPLUS >= 201703L -# if FMT_HAS_INCLUDE(<filesystem>) && \ - (!defined(FMT_CPP_LIB_FILESYSTEM) || FMT_CPP_LIB_FILESYSTEM != 0) -# include <filesystem> -# endif -# if FMT_HAS_INCLUDE(<variant>) -# include <variant> -# endif -# if FMT_HAS_INCLUDE(<optional>) -# include <optional> -# endif -# endif -// Use > instead of >= in the version check because <source_location> may be -// available after C++17 but before C++20 is marked as implemented. -# if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<source_location>) -# include <source_location> -# endif -# if FMT_CPLUSPLUS > 202002L && FMT_HAS_INCLUDE(<expected>) -# include <expected> -# endif -#endif // FMT_MODULE - -#if FMT_HAS_INCLUDE(<version>) -# include <version> -#endif - -// GCC 4 does not support FMT_HAS_INCLUDE. -#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__) -# include <cxxabi.h> -// Android NDK with gabi++ library on some architectures does not implement -// abi::__cxa_demangle(). -# ifndef __GABIXX_CXXABI_H__ -# define FMT_HAS_ABI_CXA_DEMANGLE -# endif -#endif - -// For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined. -#ifndef FMT_CPP_LIB_FILESYSTEM -# ifdef __cpp_lib_filesystem -# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem -# else -# define FMT_CPP_LIB_FILESYSTEM 0 -# endif -#endif - -#ifndef FMT_CPP_LIB_VARIANT -# ifdef __cpp_lib_variant -# define FMT_CPP_LIB_VARIANT __cpp_lib_variant -# else -# define FMT_CPP_LIB_VARIANT 0 -# endif -#endif - -#if FMT_CPP_LIB_FILESYSTEM -FMT_BEGIN_NAMESPACE - -namespace detail { - -template <typename Char, typename PathChar> -auto get_path_string(const std::filesystem::path& p, - const std::basic_string<PathChar>& native) { - if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>) - return to_utf8<wchar_t>(native, to_utf8_error_policy::replace); - else - return p.string<Char>(); -} - -template <typename Char, typename PathChar> -void write_escaped_path(basic_memory_buffer<Char>& quoted, - const std::filesystem::path& p, - const std::basic_string<PathChar>& native) { - if constexpr (std::is_same_v<Char, char> && - std::is_same_v<PathChar, wchar_t>) { - auto buf = basic_memory_buffer<wchar_t>(); - write_escaped_string<wchar_t>(std::back_inserter(buf), native); - bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()}); - FMT_ASSERT(valid, "invalid utf16"); - } else if constexpr (std::is_same_v<Char, PathChar>) { - write_escaped_string<std::filesystem::path::value_type>( - std::back_inserter(quoted), native); - } else { - write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>()); - } -} - -} // namespace detail - -FMT_EXPORT -template <typename Char> struct formatter<std::filesystem::path, Char> { - private: - format_specs specs_; - detail::arg_ref<Char> width_ref_; - bool debug_ = false; - char path_type_ = 0; - - public: - FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } - - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) { - auto it = ctx.begin(), end = ctx.end(); - if (it == end) return it; - - it = detail::parse_align(it, end, specs_); - if (it == end) return it; - - Char c = *it; - if ((c >= '0' && c <= '9') || c == '{') - it = detail::parse_width(it, end, specs_, width_ref_, ctx); - if (it != end && *it == '?') { - debug_ = true; - ++it; - } - if (it != end && (*it == 'g')) path_type_ = detail::to_ascii(*it++); - return it; - } - - template <typename FormatContext> - auto format(const std::filesystem::path& p, FormatContext& ctx) const { - auto specs = specs_; - auto path_string = - !path_type_ ? p.native() - : p.generic_string<std::filesystem::path::value_type>(); - - detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, - ctx); - if (!debug_) { - auto s = detail::get_path_string<Char>(p, path_string); - return detail::write(ctx.out(), basic_string_view<Char>(s), specs); - } - auto quoted = basic_memory_buffer<Char>(); - detail::write_escaped_path(quoted, p, path_string); - return detail::write(ctx.out(), - basic_string_view<Char>(quoted.data(), quoted.size()), - specs); - } -}; - -class path : public std::filesystem::path { - public: - auto display_string() const -> std::string { - const std::filesystem::path& base = *this; - return fmt::format(FMT_STRING("{}"), base); - } - auto system_string() const -> std::string { return string(); } - - auto generic_display_string() const -> std::string { - const std::filesystem::path& base = *this; - return fmt::format(FMT_STRING("{:g}"), base); - } - auto generic_system_string() const -> std::string { return generic_string(); } -}; - -FMT_END_NAMESPACE -#endif // FMT_CPP_LIB_FILESYSTEM - -FMT_BEGIN_NAMESPACE -FMT_EXPORT -template <std::size_t N, typename Char> -struct formatter<std::bitset<N>, Char> - : nested_formatter<basic_string_view<Char>, Char> { - private: - // Functor because C++11 doesn't support generic lambdas. - struct writer { - const std::bitset<N>& bs; - - template <typename OutputIt> - FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt { - for (auto pos = N; pos > 0; --pos) { - out = detail::write<Char>(out, bs[pos - 1] ? Char('1') : Char('0')); - } - - return out; - } - }; - - public: - template <typename FormatContext> - auto format(const std::bitset<N>& bs, FormatContext& ctx) const - -> decltype(ctx.out()) { - return this->write_padded(ctx, writer{bs}); - } -}; - -FMT_EXPORT -template <typename Char> -struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {}; -FMT_END_NAMESPACE - -#ifdef __cpp_lib_optional -FMT_BEGIN_NAMESPACE -FMT_EXPORT -template <typename T, typename Char> -struct formatter<std::optional<T>, Char, - std::enable_if_t<is_formattable<T, Char>::value>> { - private: - formatter<T, Char> underlying_; - static constexpr basic_string_view<Char> optional = - detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l', - '('>{}; - static constexpr basic_string_view<Char> none = - detail::string_literal<Char, 'n', 'o', 'n', 'e'>{}; - - template <class U> - FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set) - -> decltype(u.set_debug_format(set)) { - u.set_debug_format(set); - } - - template <class U> - FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} - - public: - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) { - maybe_set_debug_format(underlying_, true); - return underlying_.parse(ctx); - } - - template <typename FormatContext> - auto format(const std::optional<T>& opt, FormatContext& ctx) const - -> decltype(ctx.out()) { - if (!opt) return detail::write<Char>(ctx.out(), none); - - auto out = ctx.out(); - out = detail::write<Char>(out, optional); - ctx.advance_to(out); - out = underlying_.format(*opt, ctx); - return detail::write(out, ')'); - } -}; -FMT_END_NAMESPACE -#endif // __cpp_lib_optional - -#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT - -FMT_BEGIN_NAMESPACE -namespace detail { - -template <typename Char, typename OutputIt, typename T> -auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt { - if constexpr (has_to_string_view<T>::value) - return write_escaped_string<Char>(out, detail::to_string_view(v)); - if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v); - return write<Char>(out, v); -} - -} // namespace detail - -FMT_END_NAMESPACE -#endif - -#ifdef __cpp_lib_expected -FMT_BEGIN_NAMESPACE - -FMT_EXPORT -template <typename T, typename E, typename Char> -struct formatter<std::expected<T, E>, Char, - std::enable_if_t<(std::is_void<T>::value || - is_formattable<T, Char>::value) && - is_formattable<E, Char>::value>> { - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - return ctx.begin(); - } - - template <typename FormatContext> - auto format(const std::expected<T, E>& value, FormatContext& ctx) const - -> decltype(ctx.out()) { - auto out = ctx.out(); - - if (value.has_value()) { - out = detail::write<Char>(out, "expected("); - if constexpr (!std::is_void<T>::value) - out = detail::write_escaped_alternative<Char>(out, *value); - } else { - out = detail::write<Char>(out, "unexpected("); - out = detail::write_escaped_alternative<Char>(out, value.error()); - } - *out++ = ')'; - return out; - } -}; -FMT_END_NAMESPACE -#endif // __cpp_lib_expected - -#ifdef __cpp_lib_source_location -FMT_BEGIN_NAMESPACE -FMT_EXPORT -template <> struct formatter<std::source_location> { - FMT_CONSTEXPR auto parse(parse_context<>& ctx) { return ctx.begin(); } - - template <typename FormatContext> - auto format(const std::source_location& loc, FormatContext& ctx) const - -> decltype(ctx.out()) { - auto out = ctx.out(); - out = detail::write(out, loc.file_name()); - out = detail::write(out, ':'); - out = detail::write<char>(out, loc.line()); - out = detail::write(out, ':'); - out = detail::write<char>(out, loc.column()); - out = detail::write(out, ": "); - out = detail::write(out, loc.function_name()); - return out; - } -}; -FMT_END_NAMESPACE -#endif - -#if FMT_CPP_LIB_VARIANT -FMT_BEGIN_NAMESPACE -namespace detail { - -template <typename T> -using variant_index_sequence = - std::make_index_sequence<std::variant_size<T>::value>; - -template <typename> struct is_variant_like_ : std::false_type {}; -template <typename... Types> -struct is_variant_like_<std::variant<Types...>> : std::true_type {}; - -// formattable element check. -template <typename T, typename C> class is_variant_formattable_ { - template <std::size_t... Is> - static std::conjunction< - is_formattable<std::variant_alternative_t<Is, T>, C>...> - check(std::index_sequence<Is...>); - - public: - static constexpr const bool value = - decltype(check(variant_index_sequence<T>{}))::value; -}; - -} // namespace detail - -template <typename T> struct is_variant_like { - static constexpr const bool value = detail::is_variant_like_<T>::value; -}; - -template <typename T, typename C> struct is_variant_formattable { - static constexpr const bool value = - detail::is_variant_formattable_<T, C>::value; -}; - -FMT_EXPORT -template <typename Char> struct formatter<std::monostate, Char> { - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - return ctx.begin(); - } - - template <typename FormatContext> - auto format(const std::monostate&, FormatContext& ctx) const - -> decltype(ctx.out()) { - return detail::write<Char>(ctx.out(), "monostate"); - } -}; - -FMT_EXPORT -template <typename Variant, typename Char> -struct formatter< - Variant, Char, - std::enable_if_t<std::conjunction_v< - is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> { - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - return ctx.begin(); - } - - template <typename FormatContext> - auto format(const Variant& value, FormatContext& ctx) const - -> decltype(ctx.out()) { - auto out = ctx.out(); - - out = detail::write<Char>(out, "variant("); - FMT_TRY { - std::visit( - [&](const auto& v) { - out = detail::write_escaped_alternative<Char>(out, v); - }, - value); - } - FMT_CATCH(const std::bad_variant_access&) { - detail::write<Char>(out, "valueless by exception"); - } - *out++ = ')'; - return out; - } -}; -FMT_END_NAMESPACE -#endif // FMT_CPP_LIB_VARIANT - -FMT_BEGIN_NAMESPACE -FMT_EXPORT -template <> struct formatter<std::error_code> { - private: - format_specs specs_; - detail::arg_ref<char> width_ref_; - - public: - FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* { - auto it = ctx.begin(), end = ctx.end(); - if (it == end) return it; - - it = detail::parse_align(it, end, specs_); - if (it == end) return it; - - char c = *it; - if ((c >= '0' && c <= '9') || c == '{') - it = detail::parse_width(it, end, specs_, width_ref_, ctx); - return it; - } - - template <typename FormatContext> - FMT_CONSTEXPR20 auto format(const std::error_code& ec, - FormatContext& ctx) const -> decltype(ctx.out()) { - auto specs = specs_; - detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, - ctx); - memory_buffer buf; - buf.append(string_view(ec.category().name())); - buf.push_back(':'); - detail::write<char>(appender(buf), ec.value()); - return detail::write<char>(ctx.out(), string_view(buf.data(), buf.size()), - specs); - } -}; - -#if FMT_USE_RTTI -namespace detail { - -template <typename Char, typename OutputIt> -auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt { -# ifdef FMT_HAS_ABI_CXA_DEMANGLE - int status = 0; - std::size_t size = 0; - std::unique_ptr<char, void (*)(void*)> demangled_name_ptr( - abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); - - string_view demangled_name_view; - if (demangled_name_ptr) { - demangled_name_view = demangled_name_ptr.get(); - - // Normalization of stdlib inline namespace names. - // libc++ inline namespaces. - // std::__1::* -> std::* - // std::__1::__fs::* -> std::* - // libstdc++ inline namespaces. - // std::__cxx11::* -> std::* - // std::filesystem::__cxx11::* -> std::filesystem::* - if (demangled_name_view.starts_with("std::")) { - char* begin = demangled_name_ptr.get(); - char* to = begin + 5; // std:: - for (char *from = to, *end = begin + demangled_name_view.size(); - from < end;) { - // This is safe, because demangled_name is NUL-terminated. - if (from[0] == '_' && from[1] == '_') { - char* next = from + 1; - while (next < end && *next != ':') next++; - if (next[0] == ':' && next[1] == ':') { - from = next + 2; - continue; - } - } - *to++ = *from++; - } - demangled_name_view = {begin, detail::to_unsigned(to - begin)}; - } - } else { - demangled_name_view = string_view(ti.name()); - } - return detail::write_bytes<Char>(out, demangled_name_view); -# elif FMT_MSC_VERSION - const string_view demangled_name(ti.name()); - for (std::size_t i = 0; i < demangled_name.size(); ++i) { - auto sub = demangled_name; - sub.remove_prefix(i); - if (sub.starts_with("enum ")) { - i += 4; - continue; - } - if (sub.starts_with("class ") || sub.starts_with("union ")) { - i += 5; - continue; - } - if (sub.starts_with("struct ")) { - i += 6; - continue; - } - if (*sub.begin() != ' ') *out++ = *sub.begin(); - } - return out; -# else - return detail::write_bytes<Char>(out, string_view(ti.name())); -# endif -} - -} // namespace detail - -FMT_EXPORT -template <typename Char> -struct formatter<std::type_info, Char // DEPRECATED! Mixing code unit types. - > { - public: - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - return ctx.begin(); - } - - template <typename Context> - auto format(const std::type_info& ti, Context& ctx) const - -> decltype(ctx.out()) { - return detail::write_demangled_name<Char>(ctx.out(), ti); - } -}; -#endif - -FMT_EXPORT -template <typename T, typename Char> -struct formatter< - T, Char, // DEPRECATED! Mixing code unit types. - typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> { - private: - bool with_typename_ = false; - - public: - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - auto it = ctx.begin(); - auto end = ctx.end(); - if (it == end || *it == '}') return it; - if (*it == 't') { - ++it; - with_typename_ = FMT_USE_RTTI != 0; - } - return it; - } - - template <typename Context> - auto format(const std::exception& ex, Context& ctx) const - -> decltype(ctx.out()) { - auto out = ctx.out(); -#if FMT_USE_RTTI - if (with_typename_) { - out = detail::write_demangled_name<Char>(out, typeid(ex)); - *out++ = ':'; - *out++ = ' '; - } -#endif - return detail::write_bytes<Char>(out, string_view(ex.what())); - } -}; - -namespace detail { - -template <typename T, typename Enable = void> -struct has_flip : std::false_type {}; - -template <typename T> -struct has_flip<T, void_t<decltype(std::declval<T>().flip())>> - : std::true_type {}; - -template <typename T> struct is_bit_reference_like { - static constexpr const bool value = - std::is_convertible<T, bool>::value && - std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value; -}; - -#ifdef _LIBCPP_VERSION - -// Workaround for libc++ incompatibility with C++ standard. -// According to the Standard, `bitset::operator[] const` returns bool. -template <typename C> -struct is_bit_reference_like<std::__bit_const_reference<C>> { - static constexpr const bool value = true; -}; - -#endif - -} // namespace detail - -// We can't use std::vector<bool, Allocator>::reference and -// std::bitset<N>::reference because the compiler can't deduce Allocator and N -// in partial specialization. -FMT_EXPORT -template <typename BitRef, typename Char> -struct formatter<BitRef, Char, - enable_if_t<detail::is_bit_reference_like<BitRef>::value>> - : formatter<bool, Char> { - template <typename FormatContext> - FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const - -> decltype(ctx.out()) { - return formatter<bool, Char>::format(v, ctx); - } -}; - -template <typename T, typename Deleter> -auto ptr(const std::unique_ptr<T, Deleter>& p) -> const void* { - return p.get(); -} -template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* { - return p.get(); -} - -FMT_EXPORT -template <typename T, typename Char> -struct formatter<std::atomic<T>, Char, - enable_if_t<is_formattable<T, Char>::value>> - : formatter<T, Char> { - template <typename FormatContext> - auto format(const std::atomic<T>& v, FormatContext& ctx) const - -> decltype(ctx.out()) { - return formatter<T, Char>::format(v.load(), ctx); - } -}; - -#ifdef __cpp_lib_atomic_flag_test -FMT_EXPORT -template <typename Char> -struct formatter<std::atomic_flag, Char> : formatter<bool, Char> { - template <typename FormatContext> - auto format(const std::atomic_flag& v, FormatContext& ctx) const - -> decltype(ctx.out()) { - return formatter<bool, Char>::format(v.test(), ctx); - } -}; -#endif // __cpp_lib_atomic_flag_test - -FMT_EXPORT -template <typename T, typename Char> struct formatter<std::complex<T>, Char> { - private: - detail::dynamic_format_specs<Char> specs_; - - template <typename FormatContext, typename OutputIt> - FMT_CONSTEXPR auto do_format(const std::complex<T>& c, - detail::dynamic_format_specs<Char>& specs, - FormatContext& ctx, OutputIt out) const - -> OutputIt { - if (c.real() != 0) { - *out++ = Char('('); - out = detail::write<Char>(out, c.real(), specs, ctx.locale()); - specs.set_sign(sign::plus); - out = detail::write<Char>(out, c.imag(), specs, ctx.locale()); - if (!detail::isfinite(c.imag())) *out++ = Char(' '); - *out++ = Char('i'); - *out++ = Char(')'); - return out; - } - out = detail::write<Char>(out, c.imag(), specs, ctx.locale()); - if (!detail::isfinite(c.imag())) *out++ = Char(' '); - *out++ = Char('i'); - return out; - } - - public: - FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { - if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin(); - return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, - detail::type_constant<T, Char>::value); - } - - template <typename FormatContext> - auto format(const std::complex<T>& c, FormatContext& ctx) const - -> decltype(ctx.out()) { - auto specs = specs_; - if (specs.dynamic()) { - detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, - specs.width_ref, ctx); - detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision, - specs.precision_ref, ctx); - } - - if (specs.width == 0) return do_format(c, specs, ctx, ctx.out()); - auto buf = basic_memory_buffer<Char>(); - - auto outer_specs = format_specs(); - outer_specs.width = specs.width; - outer_specs.copy_fill_from(specs); - outer_specs.set_align(specs.align()); - - specs.width = 0; - specs.set_fill({}); - specs.set_align(align::none); - - do_format(c, specs, ctx, basic_appender<Char>(buf)); - return detail::write<Char>(ctx.out(), - basic_string_view<Char>(buf.data(), buf.size()), - outer_specs); - } -}; - -FMT_EXPORT -template <typename T, typename Char> -struct formatter<std::reference_wrapper<T>, Char, - enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value>> - : formatter<remove_cvref_t<T>, Char> { - template <typename FormatContext> - auto format(std::reference_wrapper<T> ref, FormatContext& ctx) const - -> decltype(ctx.out()) { - return formatter<remove_cvref_t<T>, Char>::format(ref.get(), ctx); - } -}; - -FMT_END_NAMESPACE -#endif // FMT_STD_H_ diff --git a/vendor/fmt/xchar.h b/vendor/fmt/xchar.h deleted file mode 100644 index 9f7f889d6..000000000 --- a/vendor/fmt/xchar.h +++ /dev/null @@ -1,373 +0,0 @@ -// Formatting library for C++ - optional wchar_t and exotic character support -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_XCHAR_H_ -#define FMT_XCHAR_H_ - -#include "color.h" -#include "format.h" -#include "ostream.h" -#include "ranges.h" - -#ifndef FMT_MODULE -# include <cwchar> -# if FMT_USE_LOCALE -# include <locale> -# endif -#endif - -FMT_BEGIN_NAMESPACE -namespace detail { - -template <typename T> -using is_exotic_char = bool_constant<!std::is_same<T, char>::value>; - -template <typename S, typename = void> struct format_string_char {}; - -template <typename S> -struct format_string_char< - S, void_t<decltype(sizeof(detail::to_string_view(std::declval<S>())))>> { - using type = char_t<S>; -}; - -template <typename S> -struct format_string_char< - S, enable_if_t<std::is_base_of<detail::compile_string, S>::value>> { - using type = typename S::char_type; -}; - -template <typename S> -using format_string_char_t = typename format_string_char<S>::type; - -inline auto write_loc(basic_appender<wchar_t> out, loc_value value, - const format_specs& specs, locale_ref loc) -> bool { -#if FMT_USE_LOCALE - auto& numpunct = - std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>()); - auto separator = std::wstring(); - auto grouping = numpunct.grouping(); - if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep()); - return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}}); -#endif - return false; -} -} // namespace detail - -FMT_BEGIN_EXPORT - -using wstring_view = basic_string_view<wchar_t>; -using wformat_parse_context = parse_context<wchar_t>; -using wformat_context = buffered_context<wchar_t>; -using wformat_args = basic_format_args<wformat_context>; -using wmemory_buffer = basic_memory_buffer<wchar_t>; - -template <typename Char, typename... T> struct basic_fstring { - private: - basic_string_view<Char> str_; - - static constexpr int num_static_named_args = - detail::count_static_named_args<T...>(); - - using checker = detail::format_string_checker< - Char, static_cast<int>(sizeof...(T)), num_static_named_args, - num_static_named_args != detail::count_named_args<T...>()>; - - using arg_pack = detail::arg_pack<T...>; - - public: - using t = basic_fstring; - - template <typename S, - FMT_ENABLE_IF( - std::is_convertible<const S&, basic_string_view<Char>>::value)> - FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_fstring(const S& s) : str_(s) { - if (FMT_USE_CONSTEVAL) - detail::parse_format_string<Char>(s, checker(s, arg_pack())); - } - template <typename S, - FMT_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&& - std::is_same<typename S::char_type, Char>::value)> - FMT_ALWAYS_INLINE basic_fstring(const S&) : str_(S()) { - FMT_CONSTEXPR auto sv = basic_string_view<Char>(S()); - FMT_CONSTEXPR int ignore = - (parse_format_string(sv, checker(sv, arg_pack())), 0); - detail::ignore_unused(ignore); - } - basic_fstring(runtime_format_string<Char> fmt) : str_(fmt.str) {} - - operator basic_string_view<Char>() const { return str_; } - auto get() const -> basic_string_view<Char> { return str_; } -}; - -template <typename Char, typename... T> -using basic_format_string = basic_fstring<Char, T...>; - -template <typename... T> -using wformat_string = typename basic_format_string<wchar_t, T...>::t; -inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> { - return {{s}}; -} - -template <> struct is_char<wchar_t> : std::true_type {}; -template <> struct is_char<char16_t> : std::true_type {}; -template <> struct is_char<char32_t> : std::true_type {}; - -#ifdef __cpp_char8_t -template <> struct is_char<char8_t> : bool_constant<detail::is_utf8_enabled> {}; -#endif - -template <typename... T> -constexpr auto make_wformat_args(T&... args) - -> decltype(fmt::make_format_args<wformat_context>(args...)) { - return fmt::make_format_args<wformat_context>(args...); -} - -#if !FMT_USE_NONTYPE_TEMPLATE_ARGS -inline namespace literals { -inline auto operator""_a(const wchar_t* s, size_t) -> detail::udl_arg<wchar_t> { - return {s}; -} -} // namespace literals -#endif - -template <typename It, typename Sentinel> -auto join(It begin, Sentinel end, wstring_view sep) - -> join_view<It, Sentinel, wchar_t> { - return {begin, end, sep}; -} - -template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)> -auto join(Range&& range, wstring_view sep) - -> join_view<decltype(std::begin(range)), decltype(std::end(range)), - wchar_t> { - return join(std::begin(range), std::end(range), sep); -} - -template <typename T> -auto join(std::initializer_list<T> list, wstring_view sep) - -> join_view<const T*, const T*, wchar_t> { - return join(std::begin(list), std::end(list), sep); -} - -template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)> -auto join(const Tuple& tuple, basic_string_view<wchar_t> sep) - -> tuple_join_view<wchar_t, Tuple> { - return {tuple, sep}; -} - -template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)> -auto vformat(basic_string_view<Char> fmt, - typename detail::vformat_args<Char>::type args) - -> std::basic_string<Char> { - auto buf = basic_memory_buffer<Char>(); - detail::vformat_to(buf, fmt, args); - return {buf.data(), buf.size()}; -} - -template <typename... T> -auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring { - return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); -} - -template <typename OutputIt, typename... T> -auto format_to(OutputIt out, wformat_string<T...> fmt, T&&... args) - -> OutputIt { - return vformat_to(out, fmt::wstring_view(fmt), - fmt::make_wformat_args(args...)); -} - -// Pass char_t as a default template parameter instead of using -// std::basic_string<char_t<S>> to reduce the symbol size. -template <typename S, typename... T, - typename Char = detail::format_string_char_t<S>, - FMT_ENABLE_IF(!std::is_same<Char, char>::value && - !std::is_same<Char, wchar_t>::value)> -auto format(const S& fmt, T&&... args) -> std::basic_string<Char> { - return vformat(detail::to_string_view(fmt), - fmt::make_format_args<buffered_context<Char>>(args...)); -} - -template <typename Locale, typename S, - typename Char = detail::format_string_char_t<S>, - FMT_ENABLE_IF(detail::is_locale<Locale>::value&& - detail::is_exotic_char<Char>::value)> -inline auto vformat(const Locale& loc, const S& fmt, - typename detail::vformat_args<Char>::type args) - -> std::basic_string<Char> { - auto buf = basic_memory_buffer<Char>(); - detail::vformat_to(buf, detail::to_string_view(fmt), args, - detail::locale_ref(loc)); - return {buf.data(), buf.size()}; -} - -template <typename Locale, typename S, typename... T, - typename Char = detail::format_string_char_t<S>, - FMT_ENABLE_IF(detail::is_locale<Locale>::value&& - detail::is_exotic_char<Char>::value)> -inline auto format(const Locale& loc, const S& fmt, T&&... args) - -> std::basic_string<Char> { - return vformat(loc, detail::to_string_view(fmt), - fmt::make_format_args<buffered_context<Char>>(args...)); -} - -template <typename OutputIt, typename S, - typename Char = detail::format_string_char_t<S>, - FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& - detail::is_exotic_char<Char>::value)> -auto vformat_to(OutputIt out, const S& fmt, - typename detail::vformat_args<Char>::type args) -> OutputIt { - auto&& buf = detail::get_buffer<Char>(out); - detail::vformat_to(buf, detail::to_string_view(fmt), args); - return detail::get_iterator(buf, out); -} - -template <typename OutputIt, typename S, typename... T, - typename Char = detail::format_string_char_t<S>, - FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value && - !std::is_same<Char, char>::value && - !std::is_same<Char, wchar_t>::value)> -inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { - return vformat_to(out, detail::to_string_view(fmt), - fmt::make_format_args<buffered_context<Char>>(args...)); -} - -template <typename Locale, typename S, typename OutputIt, typename... Args, - typename Char = detail::format_string_char_t<S>, - FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& - detail::is_locale<Locale>::value&& - detail::is_exotic_char<Char>::value)> -inline auto vformat_to(OutputIt out, const Locale& loc, const S& fmt, - typename detail::vformat_args<Char>::type args) - -> OutputIt { - auto&& buf = detail::get_buffer<Char>(out); - vformat_to(buf, detail::to_string_view(fmt), args, detail::locale_ref(loc)); - return detail::get_iterator(buf, out); -} - -template <typename Locale, typename OutputIt, typename S, typename... T, - typename Char = detail::format_string_char_t<S>, - bool enable = detail::is_output_iterator<OutputIt, Char>::value && - detail::is_locale<Locale>::value && - detail::is_exotic_char<Char>::value> -inline auto format_to(OutputIt out, const Locale& loc, const S& fmt, - T&&... args) -> - typename std::enable_if<enable, OutputIt>::type { - return vformat_to(out, loc, detail::to_string_view(fmt), - fmt::make_format_args<buffered_context<Char>>(args...)); -} - -template <typename OutputIt, typename Char, typename... Args, - FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& - detail::is_exotic_char<Char>::value)> -inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view<Char> fmt, - typename detail::vformat_args<Char>::type args) - -> format_to_n_result<OutputIt> { - using traits = detail::fixed_buffer_traits; - auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n); - detail::vformat_to(buf, fmt, args); - return {buf.out(), buf.count()}; -} - -template <typename OutputIt, typename S, typename... T, - typename Char = detail::format_string_char_t<S>, - FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& - detail::is_exotic_char<Char>::value)> -inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) - -> format_to_n_result<OutputIt> { - return vformat_to_n(out, n, fmt::basic_string_view<Char>(fmt), - fmt::make_format_args<buffered_context<Char>>(args...)); -} - -template <typename S, typename... T, - typename Char = detail::format_string_char_t<S>, - FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> -inline auto formatted_size(const S& fmt, T&&... args) -> size_t { - auto buf = detail::counting_buffer<Char>(); - detail::vformat_to(buf, detail::to_string_view(fmt), - fmt::make_format_args<buffered_context<Char>>(args...)); - return buf.count(); -} - -inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { - auto buf = wmemory_buffer(); - detail::vformat_to(buf, fmt, args); - buf.push_back(L'\0'); - if (std::fputws(buf.data(), f) == -1) - FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); -} - -inline void vprint(wstring_view fmt, wformat_args args) { - vprint(stdout, fmt, args); -} - -template <typename... T> -void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) { - return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); -} - -template <typename... T> void print(wformat_string<T...> fmt, T&&... args) { - return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); -} - -template <typename... T> -void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) { - return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); -} - -template <typename... T> void println(wformat_string<T...> fmt, T&&... args) { - return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); -} - -inline auto vformat(const text_style& ts, wstring_view fmt, wformat_args args) - -> std::wstring { - auto buf = wmemory_buffer(); - detail::vformat_to(buf, ts, fmt, args); - return {buf.data(), buf.size()}; -} - -template <typename... T> -inline auto format(const text_style& ts, wformat_string<T...> fmt, T&&... args) - -> std::wstring { - return fmt::vformat(ts, fmt, fmt::make_wformat_args(args...)); -} - -template <typename... T> -FMT_DEPRECATED void print(std::FILE* f, const text_style& ts, - wformat_string<T...> fmt, const T&... args) { - vprint(f, ts, fmt, fmt::make_wformat_args(args...)); -} - -template <typename... T> -FMT_DEPRECATED void print(const text_style& ts, wformat_string<T...> fmt, - const T&... args) { - return print(stdout, ts, fmt, args...); -} - -inline void vprint(std::wostream& os, wstring_view fmt, wformat_args args) { - auto buffer = basic_memory_buffer<wchar_t>(); - detail::vformat_to(buffer, fmt, args); - detail::write_buffer(os, buffer); -} - -template <typename... T> -void print(std::wostream& os, wformat_string<T...> fmt, T&&... args) { - vprint(os, fmt, fmt::make_format_args<buffered_context<wchar_t>>(args...)); -} - -template <typename... T> -void println(std::wostream& os, wformat_string<T...> fmt, T&&... args) { - print(os, L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); -} - -/// Converts `value` to `std::wstring` using the default format for type `T`. -template <typename T> inline auto to_wstring(const T& value) -> std::wstring { - return format(FMT_STRING(L"{}"), value); -} -FMT_END_EXPORT -FMT_END_NAMESPACE - -#endif // FMT_XCHAR_H_ diff --git a/vendor/update.toml b/vendor/update.toml index 5b3d57df6..28bff8b8c 100644 --- a/vendor/update.toml +++ b/vendor/update.toml @@ -10,7 +10,7 @@ website = "https://www.openwall.com/crypt/" [fmt] author = "Victor Zverovich and fmt contributors" depth = 2 -files = "{include/fmt/*.h,LICENSE.rst,src/format.cc}" +files = "{include/fmt/{base,color,compile,core,format,format-inl}.h,LICENSE,src/format.cc}" git = "https://github.com/fmtlib/fmt/" license = "MIT License" |
