aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Sadie Powell2025-04-13 17:03:08 +0100
committerGravatar Sadie Powell2025-04-13 17:03:08 +0100
commitd0e321b92c55902ccb3ca98ddd8553cb57e55c77 (patch)
treed7e0f9cdbe7d292b8409b0156da449eb9299c74e
parentMerge branch 'insp4' into master. (diff)
parentRemove the {fmt} headers that we don't use. (diff)
Merge branch 'insp4' into master.
-rw-r--r--make/directive.pm18
-rw-r--r--modules/httpd.cpp9
-rw-r--r--modules/spanningtree/utils.cpp6
-rw-r--r--modules/websocket.cpp11
-rw-r--r--vendor/fmt/LICENSE (renamed from vendor/fmt/LICENSE.rst)0
-rw-r--r--vendor/fmt/args.h220
-rw-r--r--vendor/fmt/chrono.h2338
-rw-r--r--vendor/fmt/os.h427
-rw-r--r--vendor/fmt/ostream.h166
-rw-r--r--vendor/fmt/printf.h633
-rw-r--r--vendor/fmt/ranges.h850
-rw-r--r--vendor/fmt/std.h726
-rw-r--r--vendor/fmt/xchar.h373
-rw-r--r--vendor/update.toml2
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(&gtm);
- std::tm ltm = gmtime(gt);
- std::time_t lt = std::mktime(&ltm);
- 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"