Browse Source

Update fmtlib to 8.1.1 + spdlog to 1.11.0 + jinja2cpp to 1.2.1

dakovalkov 2 years ago
parent
commit
cd21459f6e

+ 1 - 0
contrib/libs/fmt/CMakeLists.darwin.txt

@@ -10,6 +10,7 @@
 add_library(contrib-libs-fmt)
 target_compile_options(contrib-libs-fmt PUBLIC
   -DFMT_EXPORT
+  -DFMT_CONSTEVAL=
 )
 target_compile_options(contrib-libs-fmt PRIVATE
   -Wno-everything

+ 1 - 0
contrib/libs/fmt/CMakeLists.linux-aarch64.txt

@@ -10,6 +10,7 @@
 add_library(contrib-libs-fmt)
 target_compile_options(contrib-libs-fmt PUBLIC
   -DFMT_EXPORT
+  -DFMT_CONSTEVAL=
 )
 target_compile_options(contrib-libs-fmt PRIVATE
   -Wno-everything

+ 1 - 0
contrib/libs/fmt/CMakeLists.linux.txt

@@ -10,6 +10,7 @@
 add_library(contrib-libs-fmt)
 target_compile_options(contrib-libs-fmt PUBLIC
   -DFMT_EXPORT
+  -DFMT_CONSTEVAL=
 )
 target_compile_options(contrib-libs-fmt PRIVATE
   -Wno-everything

File diff suppressed because it is too large
+ 1073 - 0
contrib/libs/fmt/ChangeLog.rst


+ 35 - 13
contrib/libs/fmt/README.rst

@@ -1,10 +1,16 @@
 {fmt}
 =====
 
-.. image:: https://travis-ci.org/fmtlib/fmt.png?branch=master
-   :target: https://travis-ci.org/fmtlib/fmt
+.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg
+   :target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux
 
-.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v
+.. image:: https://github.com/fmtlib/fmt/workflows/macos/badge.svg
+   :target: https://github.com/fmtlib/fmt/actions?query=workflow%3Amacos
+
+.. image:: https://github.com/fmtlib/fmt/workflows/windows/badge.svg
+   :target: https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows
+
+.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v?svg=true
    :target: https://ci.appveyor.com/project/vitaut/fmt
 
 .. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg
@@ -20,9 +26,9 @@
 **{fmt}** is an open-source formatting library providing a fast and safe
 alternative to C stdio and C++ iostreams.
 
-If you like this project, please consider donating to BYSOL,
-an initiative to help victims of political repressions in Belarus:
-https://www.facebook.com/donate/759400044849707/108388587646909/.
+If you like this project, please consider donating to the BYSOL
+Foundation that helps victims of political repressions in Belarus:
+https://bysol.org/en/bs/general/.
 
 `Documentation <https://fmt.dev>`__
 
@@ -131,16 +137,16 @@ Output::
 
 Output::
 
-    {1, 2, 3}
+    [1, 2, 3]
 
 **Check a format string at compile time**
 
 .. code:: c++
 
-    std::string s = fmt::format(FMT_STRING("{:d}"), "don't panic");
+    std::string s = fmt::format("{:d}", "I am not a number");
 
-This gives a compile-time error because ``d`` is an invalid format specifier for
-a string.
+This gives a compile-time error in C++20 because ``d`` is an invalid format
+specifier for a string.
 
 **Write a file from a single thread**
 
@@ -199,7 +205,7 @@ The above results were generated by building ``tinyformat_test.cpp`` on macOS
 best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
 or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
 further details refer to the `source
-<https://github.com/fmtlib/format-benchmark/blob/master/tinyformat_test.cpp>`_.
+<https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc>`_.
 
 {fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on
 floating-point formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
@@ -283,6 +289,13 @@ Then you can run the speed test::
 or the bloat test::
 
     $ make bloat-test
+    
+Migrating code
+--------------
+
+`clang-tidy-fmt <https://github.com/mikecrowe/clang-tidy-fmt>`_ provides clang
+tidy checks for converting occurrences of ``printf`` and ``fprintf`` to
+``fmt::print``.
 
 Projects using this library
 ---------------------------
@@ -290,6 +303,8 @@ Projects using this library
 * `0 A.D. <https://play0ad.com/>`_: a free, open-source, cross-platform
   real-time strategy game
 
+* `2GIS <https://2gis.ru/>`_: free business listings with a city map
+
 * `AMPL/MP <https://github.com/ampl/mp>`_:
   an open-source library for mathematical programming
 
@@ -310,7 +325,7 @@ Projects using this library
 * `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: analytical database
   management system
 
-* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater
+* `CUAUV <https://cuauv.org/>`_: Cornell University's autonomous underwater
   vehicle
 
 * `Drake <https://drake.mit.edu/>`_: a planning, control, and analysis toolbox
@@ -321,8 +336,15 @@ Projects using this library
 
 * `FiveM <https://fivem.net/>`_: a modification framework for GTA V
 
+* `fmtlog <https://github.com/MengRao/fmtlog>`_: a performant fmtlib-style
+  logging library with latency in nanoseconds
+
 * `Folly <https://github.com/facebook/folly>`_: Facebook open-source library
 
+* `Grand Mountain Adventure
+  <https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/>`_:
+  A beautiful open-world ski & snowboarding game
+
 * `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
   Player vs Player Gaming Network with tweaks
 
@@ -447,7 +469,7 @@ Boost Format
 
 This is a very powerful library which supports both ``printf``-like format
 strings and positional arguments. Its main drawback is performance. According to
-various, benchmarks it is much slower than other methods considered here. Boost
+various benchmarks, it is much slower than other methods considered here. Boost
 Format also has excessive build times and severe code bloat issues (see
 `Benchmarks`_).
 

+ 234 - 0
contrib/libs/fmt/include/fmt/args.h

@@ -0,0 +1,234 @@
+// Formatting library for C++ - dynamic format arguments
+//
+// 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_
+
+#include <functional>  // std::reference_wrapper
+#include <memory>      // std::unique_ptr
+#include <vector>
+
+#include "core.h"
+
+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> const T& unwrap(const T& v) { return v; }
+template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) {
+  return static_cast<const T&>(v);
+}
+
+class dynamic_arg_list {
+  // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
+  // templates it doesn't complain about inability to deduce single translation
+  // unit for placing vtable. So storage_node_base is made a fake template.
+  template <typename = void> struct node {
+    virtual ~node() = default;
+    std::unique_ptr<node<>> next;
+  };
+
+  template <typename T> struct typed_node : node<> {
+    T value;
+
+    template <typename Arg>
+    FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
+
+    template <typename Char>
+    FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
+        : value(arg.data(), arg.size()) {}
+  };
+
+  std::unique_ptr<node<>> head_;
+
+ public:
+  template <typename T, typename Arg> const T& push(const Arg& arg) {
+    auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
+    auto& value = new_node->value;
+    new_node->next = std::move(head_);
+    head_ = std::move(new_node);
+    return value;
+  }
+};
+}  // namespace detail
+
+/**
+  \rst
+  A dynamic version of `fmt::format_arg_store`.
+  It's equipped with a storage to potentially temporary objects which lifetimes
+  could be shorter than the format arguments object.
+
+  It can be implicitly converted into `~fmt::basic_format_args` for passing
+  into type-erased formatting functions such as `~fmt::vformat`.
+  \endrst
+ */
+template <typename Context>
+class dynamic_format_arg_store
+#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
+    // Workaround a GCC template argument substitution bug.
+    : public basic_format_args<Context>
+#endif
+{
+ private:
+  using char_type = typename Context::char_type;
+
+  template <typename T> struct need_copy {
+    static constexpr detail::type mapped_type =
+        detail::mapped_type_constant<T, Context>::value;
+
+    enum {
+      value = !(detail::is_reference_wrapper<T>::value ||
+                std::is_same<T, basic_string_view<char_type>>::value ||
+                std::is_same<T, detail::std_string_view<char_type>>::value ||
+                (mapped_type != detail::type::cstring_type &&
+                 mapped_type != detail::type::string_type &&
+                 mapped_type != detail::type::custom_type))
+    };
+  };
+
+  template <typename T>
+  using stored_type = conditional_t<detail::is_string<T>::value &&
+                                        !has_formatter<T, Context>::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>;
+
+  unsigned long long get_types() const {
+    return detail::is_unpacked_bit | data_.size() |
+           (named_info_.empty()
+                ? 0ULL
+                : static_cast<unsigned long long>(detail::has_named_args_bit));
+  }
+
+  const basic_format_arg<Context>* data() const {
+    return named_info_.empty() ? data_.data() : data_.data() + 1;
+  }
+
+  template <typename T> void emplace_arg(const T& arg) {
+    data_.emplace_back(detail::make_arg<Context>(arg));
+  }
+
+  template <typename T>
+  void emplace_arg(const detail::named_arg<char_type, T>& arg) {
+    if (named_info_.empty()) {
+      constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr};
+      data_.insert(data_.begin(), {zero_ptr, 0});
+    }
+    data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value)));
+    auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
+      data->pop_back();
+    };
+    std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
+        guard{&data_, pop_one};
+    named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
+    data_[0].value_.named_args = {named_info_.data(), named_info_.size()};
+    guard.release();
+  }
+
+ public:
+  constexpr dynamic_format_arg_store() = default;
+
+  /**
+    \rst
+    Adds an argument into the dynamic store for later passing to a formatting
+    function.
+
+    Note that custom types and string types (but not string views) are copied
+    into the store dynamically allocating memory if necessary.
+
+    **Example**::
+
+      fmt::dynamic_format_arg_store<fmt::format_context> store;
+      store.push_back(42);
+      store.push_back("abc");
+      store.push_back(1.5f);
+      std::string result = fmt::vformat("{} and {} and {}", store);
+    \endrst
+  */
+  template <typename T> void push_back(const T& arg) {
+    if (detail::const_check(need_copy<T>::value))
+      emplace_arg(dynamic_args_.push<stored_type<T>>(arg));
+    else
+      emplace_arg(detail::unwrap(arg));
+  }
+
+  /**
+    \rst
+    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"
+    \endrst
+  */
+  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_type<T>>(arg.value)));
+    } else {
+      emplace_arg(fmt::arg(arg_name, arg.value));
+    }
+  }
+
+  /** Erase all elements from the store */
+  void clear() {
+    data_.clear();
+    named_info_.clear();
+    dynamic_args_ = detail::dynamic_arg_list();
+  }
+
+  /**
+    \rst
+    Reserves space to store at least *new_cap* arguments including
+    *new_cap_named* named arguments.
+    \endrst
+  */
+  void reserve(size_t new_cap, size_t new_cap_named) {
+    FMT_ASSERT(new_cap >= new_cap_named,
+               "Set of arguments includes set of named arguments");
+    data_.reserve(new_cap);
+    named_info_.reserve(new_cap_named);
+  }
+};
+
+FMT_END_NAMESPACE
+
+#endif  // FMT_ARGS_H_

File diff suppressed because it is too large
+ 852 - 120
contrib/libs/fmt/include/fmt/chrono.h


+ 96 - 61
contrib/libs/fmt/include/fmt/color.h

@@ -10,7 +10,15 @@
 
 #include "format.h"
 
+// __declspec(deprecated) is broken in some MSVC versions.
+#if FMT_MSC_VER
+#  define FMT_DEPRECATED_NONMSVC
+#else
+#  define FMT_DEPRECATED_NONMSVC FMT_DEPRECATED
+#endif
+
 FMT_BEGIN_NAMESPACE
+FMT_MODULE_EXPORT_BEGIN
 
 enum class color : uint32_t {
   alice_blue = 0xF0F8FF,               // rgb(240,248,255)
@@ -177,9 +185,13 @@ enum class terminal_color : uint8_t {
 
 enum class emphasis : uint8_t {
   bold = 1,
-  italic = 1 << 1,
-  underline = 1 << 2,
-  strikethrough = 1 << 3
+  faint = 1 << 1,
+  italic = 1 << 2,
+  underline = 1 << 3,
+  blink = 1 << 4,
+  reverse = 1 << 5,
+  conceal = 1 << 6,
+  strikethrough = 1 << 7,
 };
 
 // rgb is a struct for red, green and blue colors.
@@ -198,7 +210,7 @@ struct rgb {
   uint8_t b;
 };
 
-namespace detail {
+FMT_BEGIN_DETAIL_NAMESPACE
 
 // color is a struct of either a rgb color or a terminal color.
 struct color_type {
@@ -221,9 +233,10 @@ struct color_type {
     uint32_t rgb_color;
   } value;
 };
-}  // namespace detail
 
-// Experimental text formatting support.
+FMT_END_DETAIL_NAMESPACE
+
+/** A text style consisting of foreground and background colors and emphasis. */
 class text_style {
  public:
   FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
@@ -260,33 +273,14 @@ class text_style {
     return lhs |= rhs;
   }
 
-  FMT_CONSTEXPR text_style& operator&=(const text_style& rhs) {
-    if (!set_foreground_color) {
-      set_foreground_color = rhs.set_foreground_color;
-      foreground_color = rhs.foreground_color;
-    } else if (rhs.set_foreground_color) {
-      if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
-        FMT_THROW(format_error("can't AND a terminal color"));
-      foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
-    }
-
-    if (!set_background_color) {
-      set_background_color = rhs.set_background_color;
-      background_color = rhs.background_color;
-    } else if (rhs.set_background_color) {
-      if (!background_color.is_rgb || !rhs.background_color.is_rgb)
-        FMT_THROW(format_error("can't AND a terminal color"));
-      background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
-    }
-
-    ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
-                                static_cast<uint8_t>(rhs.ems));
-    return *this;
+  FMT_DEPRECATED_NONMSVC FMT_CONSTEXPR text_style& operator&=(
+      const text_style& rhs) {
+    return and_assign(rhs);
   }
 
-  friend FMT_CONSTEXPR text_style operator&(text_style lhs,
-                                            const text_style& rhs) {
-    return lhs &= rhs;
+  FMT_DEPRECATED_NONMSVC friend FMT_CONSTEXPR text_style
+  operator&(text_style lhs, const text_style& rhs) {
+    return lhs.and_assign(rhs);
   }
 
   FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
@@ -326,8 +320,34 @@ class text_style {
     }
   }
 
+  // DEPRECATED!
+  FMT_CONSTEXPR text_style& and_assign(const text_style& rhs) {
+    if (!set_foreground_color) {
+      set_foreground_color = rhs.set_foreground_color;
+      foreground_color = rhs.foreground_color;
+    } else if (rhs.set_foreground_color) {
+      if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
+        FMT_THROW(format_error("can't AND a terminal color"));
+      foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
+    }
+
+    if (!set_background_color) {
+      set_background_color = rhs.set_background_color;
+      background_color = rhs.background_color;
+    } else if (rhs.set_background_color) {
+      if (!background_color.is_rgb || !rhs.background_color.is_rgb)
+        FMT_THROW(format_error("can't AND a terminal color"));
+      background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
+    }
+
+    ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
+                                static_cast<uint8_t>(rhs.ems));
+    return *this;
+  }
+
   friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground)
       FMT_NOEXCEPT;
+
   friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
       FMT_NOEXCEPT;
 
@@ -338,19 +358,22 @@ class text_style {
   emphasis ems;
 };
 
-FMT_CONSTEXPR text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
-  return text_style(/*is_foreground=*/true, foreground);
+/** Creates a text style from the foreground (text) color. */
+FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
+  return text_style(true, foreground);
 }
 
-FMT_CONSTEXPR text_style bg(detail::color_type background) FMT_NOEXCEPT {
-  return text_style(/*is_foreground=*/false, background);
+/** Creates a text style from the background color. */
+FMT_CONSTEXPR inline text_style bg(detail::color_type background) FMT_NOEXCEPT {
+  return text_style(false, background);
 }
 
-FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
+FMT_CONSTEXPR inline text_style operator|(emphasis lhs,
+                                          emphasis rhs) FMT_NOEXCEPT {
   return text_style(lhs) | rhs;
 }
 
-namespace detail {
+FMT_BEGIN_DETAIL_NAMESPACE
 
 template <typename Char> struct ansi_color_escape {
   FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
@@ -358,7 +381,7 @@ template <typename Char> struct ansi_color_escape {
     // If we have a terminal color, we need to output another escape code
     // sequence.
     if (!text_color.is_rgb) {
-      bool is_background = esc == detail::data::background_color;
+      bool is_background = esc == string_view("\x1b[48;2;");
       uint32_t value = text_color.value.term_color;
       // Background ASCII codes are the same as the foreground ones but with
       // 10 more.
@@ -390,16 +413,18 @@ template <typename Char> struct ansi_color_escape {
     buffer[19] = static_cast<Char>(0);
   }
   FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
-    uint8_t em_codes[4] = {};
-    uint8_t em_bits = static_cast<uint8_t>(em);
-    if (em_bits & static_cast<uint8_t>(emphasis::bold)) em_codes[0] = 1;
-    if (em_bits & static_cast<uint8_t>(emphasis::italic)) em_codes[1] = 3;
-    if (em_bits & static_cast<uint8_t>(emphasis::underline)) em_codes[2] = 4;
-    if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
-      em_codes[3] = 9;
+    uint8_t em_codes[num_emphases] = {};
+    if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
+    if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
+    if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3;
+    if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4;
+    if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5;
+    if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7;
+    if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8;
+    if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9;
 
     size_t index = 0;
-    for (int i = 0; i < 4; ++i) {
+    for (size_t i = 0; i < num_emphases; ++i) {
       if (!em_codes[i]) continue;
       buffer[index++] = static_cast<Char>('\x1b');
       buffer[index++] = static_cast<Char>('[');
@@ -411,12 +436,13 @@ template <typename Char> struct ansi_color_escape {
   FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
 
   FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
-  FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT {
+  FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT {
     return buffer + std::char_traits<Char>::length(buffer);
   }
 
  private:
-  Char buffer[7u + 3u * 4u + 1u];
+  static constexpr size_t num_emphases = 8;
+  Char buffer[7u + 3u * num_emphases + 1u];
 
   static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
                                    char delimiter) FMT_NOEXCEPT {
@@ -425,18 +451,22 @@ template <typename Char> struct ansi_color_escape {
     out[2] = static_cast<Char>('0' + c % 10);
     out[3] = static_cast<Char>(delimiter);
   }
+  static FMT_CONSTEXPR bool has_emphasis(emphasis em,
+                                         emphasis mask) FMT_NOEXCEPT {
+    return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
+  }
 };
 
 template <typename Char>
 FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
     detail::color_type foreground) FMT_NOEXCEPT {
-  return ansi_color_escape<Char>(foreground, detail::data::foreground_color);
+  return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
 }
 
 template <typename Char>
 FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
     detail::color_type background) FMT_NOEXCEPT {
-  return ansi_color_escape<Char>(background, detail::data::background_color);
+  return ansi_color_escape<Char>(background, "\x1b[48;2;");
 }
 
 template <typename Char>
@@ -455,18 +485,17 @@ inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
 }
 
 template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
-  fputs(detail::data::reset_color, stream);
+  fputs("\x1b[0m", stream);
 }
 
 template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
-  fputs(detail::data::wreset_color, stream);
+  fputs(L"\x1b[0m", stream);
 }
 
 template <typename Char>
 inline void reset_color(buffer<Char>& buffer) FMT_NOEXCEPT {
-  const char* begin = data::reset_color;
-  const char* end = begin + sizeof(data::reset_color) - 1;
-  buffer.append(begin, end);
+  auto reset_color = string_view("\x1b[0m");
+  buffer.append(reset_color.begin(), reset_color.end());
 }
 
 template <typename Char>
@@ -489,10 +518,11 @@ void vformat_to(buffer<Char>& buf, const text_style& ts,
     auto background = detail::make_background_color<Char>(ts.get_background());
     buf.append(background.begin(), background.end());
   }
-  detail::vformat_to(buf, format_str, args);
+  detail::vformat_to(buf, format_str, args, {});
   if (has_style) detail::reset_color<Char>(buf);
 }
-}  // namespace detail
+
+FMT_END_DETAIL_NAMESPACE
 
 template <typename S, typename Char = char_t<S>>
 void vprint(std::FILE* f, const text_style& ts, const S& format,
@@ -523,11 +553,15 @@ void print(std::FILE* f, const text_style& ts, const S& format_str,
 }
 
 /**
+  \rst
   Formats a string and prints it to stdout using ANSI escape sequences to
   specify text formatting.
-  Example:
+
+  **Example**::
+
     fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
                "Elapsed time: {0:.2f} seconds", 1.23);
+  \endrst
  */
 template <typename S, typename... Args,
           FMT_ENABLE_IF(detail::is_string<S>::value)>
@@ -559,8 +593,8 @@ inline std::basic_string<Char> vformat(
 template <typename S, typename... Args, typename Char = char_t<S>>
 inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
                                       const Args&... args) {
-  return vformat(ts, to_string_view(format_str),
-                 fmt::make_args_checked<Args...>(format_str, args...));
+  return fmt::vformat(ts, to_string_view(format_str),
+                      fmt::make_args_checked<Args...>(format_str, args...));
 }
 
 /**
@@ -571,7 +605,7 @@ template <typename OutputIt, typename Char,
 OutputIt vformat_to(
     OutputIt out, const text_style& ts, basic_string_view<Char> format_str,
     basic_format_args<buffer_context<type_identity_t<Char>>> args) {
-  decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
+  auto&& buf = detail::get_buffer<Char>(out);
   detail::vformat_to(buf, ts, format_str, args);
   return detail::get_iterator(buf);
 }
@@ -598,6 +632,7 @@ inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
                     fmt::make_args_checked<Args...>(format_str, args...));
 }
 
+FMT_MODULE_EXPORT_END
 FMT_END_NAMESPACE
 
 #endif  // FMT_COLOR_H_

+ 370 - 429
contrib/libs/fmt/include/fmt/compile.h

@@ -8,362 +8,178 @@
 #ifndef FMT_COMPILE_H_
 #define FMT_COMPILE_H_
 
-#include <vector>
-
 #include "format.h"
 
 FMT_BEGIN_NAMESPACE
 namespace detail {
 
-// A compile-time string which is compiled into fast formatting code.
-class compiled_string {};
-
-template <typename S>
-struct is_compiled_string : std::is_base_of<compiled_string, S> {};
-
-/**
-  \rst
-  Converts a string literal *s* into a format string that will be parsed at
-  compile time and converted into efficient formatting code. Requires C++17
-  ``constexpr if`` compiler support.
-
-  **Example**::
-
-    // Converts 42 into std::string using the most efficient method and no
-    // runtime format string processing.
-    std::string s = fmt::format(FMT_COMPILE("{}"), 42);
-  \endrst
- */
-#define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::detail::compiled_string)
-
-template <typename T, typename... Tail>
-const T& first(const T& value, const Tail&...) {
-  return value;
-}
-
-// Part of a compiled format string. It can be either literal text or a
-// replacement field.
-template <typename Char> struct format_part {
-  enum class kind { arg_index, arg_name, text, replacement };
+// An output iterator that counts the number of objects written to it and
+// discards them.
+class counting_iterator {
+ private:
+  size_t count_;
 
-  struct replacement {
-    arg_ref<Char> arg_id;
-    dynamic_format_specs<Char> specs;
+ public:
+  using iterator_category = std::output_iterator_tag;
+  using difference_type = std::ptrdiff_t;
+  using pointer = void;
+  using reference = void;
+  using _Unchecked_type = counting_iterator;  // Mark iterator as checked.
+
+  struct value_type {
+    template <typename T> void operator=(const T&) {}
   };
 
-  kind part_kind;
-  union value {
-    int arg_index;
-    basic_string_view<Char> str;
-    replacement repl;
-
-    FMT_CONSTEXPR value(int index = 0) : arg_index(index) {}
-    FMT_CONSTEXPR value(basic_string_view<Char> s) : str(s) {}
-    FMT_CONSTEXPR value(replacement r) : repl(r) {}
-  } val;
-  // Position past the end of the argument id.
-  const Char* arg_id_end = nullptr;
+  counting_iterator() : count_(0) {}
 
-  FMT_CONSTEXPR format_part(kind k = kind::arg_index, value v = {})
-      : part_kind(k), val(v) {}
+  size_t count() const { return count_; }
 
-  static FMT_CONSTEXPR format_part make_arg_index(int index) {
-    return format_part(kind::arg_index, index);
-  }
-  static FMT_CONSTEXPR format_part make_arg_name(basic_string_view<Char> name) {
-    return format_part(kind::arg_name, name);
+  counting_iterator& operator++() {
+    ++count_;
+    return *this;
   }
-  static FMT_CONSTEXPR format_part make_text(basic_string_view<Char> text) {
-    return format_part(kind::text, text);
+  counting_iterator operator++(int) {
+    auto it = *this;
+    ++*this;
+    return it;
   }
-  static FMT_CONSTEXPR format_part make_replacement(replacement repl) {
-    return format_part(kind::replacement, repl);
+
+  friend counting_iterator operator+(counting_iterator it, difference_type n) {
+    it.count_ += static_cast<size_t>(n);
+    return it;
   }
+
+  value_type operator*() const { return {}; }
 };
 
-template <typename Char> struct part_counter {
-  unsigned num_parts = 0;
+template <typename Char, typename InputIt>
+inline counting_iterator copy_str(InputIt begin, InputIt end,
+                                  counting_iterator it) {
+  return it + (end - begin);
+}
 
-  FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
-    if (begin != end) ++num_parts;
-  }
+template <typename OutputIt> class truncating_iterator_base {
+ protected:
+  OutputIt out_;
+  size_t limit_;
+  size_t count_ = 0;
 
-  FMT_CONSTEXPR int on_arg_id() { return ++num_parts, 0; }
-  FMT_CONSTEXPR int on_arg_id(int) { return ++num_parts, 0; }
-  FMT_CONSTEXPR int on_arg_id(basic_string_view<Char>) {
-    return ++num_parts, 0;
-  }
+  truncating_iterator_base() : out_(), limit_(0) {}
 
-  FMT_CONSTEXPR void on_replacement_field(int, const Char*) {}
-
-  FMT_CONSTEXPR const Char* on_format_specs(int, const Char* begin,
-                                            const Char* end) {
-    // Find the matching brace.
-    unsigned brace_counter = 0;
-    for (; begin != end; ++begin) {
-      if (*begin == '{') {
-        ++brace_counter;
-      } else if (*begin == '}') {
-        if (brace_counter == 0u) break;
-        --brace_counter;
-      }
-    }
-    return begin;
-  }
+  truncating_iterator_base(OutputIt out, size_t limit)
+      : out_(out), limit_(limit) {}
 
-  FMT_CONSTEXPR void on_error(const char*) {}
+ public:
+  using iterator_category = std::output_iterator_tag;
+  using value_type = typename std::iterator_traits<OutputIt>::value_type;
+  using difference_type = std::ptrdiff_t;
+  using pointer = void;
+  using reference = void;
+  using _Unchecked_type =
+      truncating_iterator_base;  // Mark iterator as checked.
+
+  OutputIt base() const { return out_; }
+  size_t count() const { return count_; }
 };
 
-// Counts the number of parts in a format string.
-template <typename Char>
-FMT_CONSTEXPR unsigned count_parts(basic_string_view<Char> format_str) {
-  part_counter<Char> counter;
-  parse_format_string<true>(format_str, counter);
-  return counter.num_parts;
-}
-
-template <typename Char, typename PartHandler>
-class format_string_compiler : public error_handler {
- private:
-  using part = format_part<Char>;
+// An output iterator that truncates the output and counts the number of objects
+// written to it.
+template <typename OutputIt,
+          typename Enable = typename std::is_void<
+              typename std::iterator_traits<OutputIt>::value_type>::type>
+class truncating_iterator;
 
-  PartHandler handler_;
-  part part_;
-  basic_string_view<Char> format_str_;
-  basic_format_parse_context<Char> parse_context_;
+template <typename OutputIt>
+class truncating_iterator<OutputIt, std::false_type>
+    : public truncating_iterator_base<OutputIt> {
+  mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
 
  public:
-  FMT_CONSTEXPR format_string_compiler(basic_string_view<Char> format_str,
-                                       PartHandler handler)
-      : handler_(handler),
-        format_str_(format_str),
-        parse_context_(format_str) {}
-
-  FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
-    if (begin != end)
-      handler_(part::make_text({begin, to_unsigned(end - begin)}));
-  }
+  using value_type = typename truncating_iterator_base<OutputIt>::value_type;
 
-  FMT_CONSTEXPR int on_arg_id() {
-    part_ = part::make_arg_index(parse_context_.next_arg_id());
-    return 0;
-  }
-
-  FMT_CONSTEXPR int on_arg_id(int id) {
-    parse_context_.check_arg_id(id);
-    part_ = part::make_arg_index(id);
-    return 0;
-  }
+  truncating_iterator() = default;
 
-  FMT_CONSTEXPR int on_arg_id(basic_string_view<Char> id) {
-    part_ = part::make_arg_name(id);
-    return 0;
-  }
+  truncating_iterator(OutputIt out, size_t limit)
+      : truncating_iterator_base<OutputIt>(out, limit) {}
 
-  FMT_CONSTEXPR void on_replacement_field(int, const Char* ptr) {
-    part_.arg_id_end = ptr;
-    handler_(part_);
+  truncating_iterator& operator++() {
+    if (this->count_++ < this->limit_) ++this->out_;
+    return *this;
   }
 
-  FMT_CONSTEXPR const Char* on_format_specs(int, const Char* begin,
-                                            const Char* end) {
-    auto repl = typename part::replacement();
-    dynamic_specs_handler<basic_format_parse_context<Char>> handler(
-        repl.specs, parse_context_);
-    auto it = parse_format_specs(begin, end, handler);
-    if (*it != '}') on_error("missing '}' in format string");
-    repl.arg_id = part_.part_kind == part::kind::arg_index
-                      ? arg_ref<Char>(part_.val.arg_index)
-                      : arg_ref<Char>(part_.val.str);
-    auto part = part::make_replacement(repl);
-    part.arg_id_end = begin;
-    handler_(part);
+  truncating_iterator operator++(int) {
+    auto it = *this;
+    ++*this;
     return it;
   }
-};
-
-// Compiles a format string and invokes handler(part) for each parsed part.
-template <bool IS_CONSTEXPR, typename Char, typename PartHandler>
-FMT_CONSTEXPR void compile_format_string(basic_string_view<Char> format_str,
-                                         PartHandler handler) {
-  parse_format_string<IS_CONSTEXPR>(
-      format_str,
-      format_string_compiler<Char, PartHandler>(format_str, handler));
-}
 
-template <typename OutputIt, typename Context, typename Id>
-void format_arg(
-    basic_format_parse_context<typename Context::char_type>& parse_ctx,
-    Context& ctx, Id arg_id) {
-  ctx.advance_to(visit_format_arg(
-      arg_formatter<OutputIt, typename Context::char_type>(ctx, &parse_ctx),
-      ctx.arg(arg_id)));
-}
-
-// vformat_to is defined in a subnamespace to prevent ADL.
-namespace cf {
-template <typename Context, typename OutputIt, typename CompiledFormat>
-auto vformat_to(OutputIt out, CompiledFormat& cf,
-                basic_format_args<Context> args) -> typename Context::iterator {
-  using char_type = typename Context::char_type;
-  basic_format_parse_context<char_type> parse_ctx(
-      to_string_view(cf.format_str_));
-  Context ctx(out, args);
-
-  const auto& parts = cf.parts();
-  for (auto part_it = std::begin(parts); part_it != std::end(parts);
-       ++part_it) {
-    const auto& part = *part_it;
-    const auto& value = part.val;
-
-    using format_part_t = format_part<char_type>;
-    switch (part.part_kind) {
-    case format_part_t::kind::text: {
-      const auto text = value.str;
-      auto output = ctx.out();
-      auto&& it = reserve(output, text.size());
-      it = std::copy_n(text.begin(), text.size(), it);
-      ctx.advance_to(output);
-      break;
-    }
-
-    case format_part_t::kind::arg_index:
-      advance_to(parse_ctx, part.arg_id_end);
-      detail::format_arg<OutputIt>(parse_ctx, ctx, value.arg_index);
-      break;
-
-    case format_part_t::kind::arg_name:
-      advance_to(parse_ctx, part.arg_id_end);
-      detail::format_arg<OutputIt>(parse_ctx, ctx, value.str);
-      break;
-
-    case format_part_t::kind::replacement: {
-      const auto& arg_id_value = value.repl.arg_id.val;
-      const auto arg = value.repl.arg_id.kind == arg_id_kind::index
-                           ? ctx.arg(arg_id_value.index)
-                           : ctx.arg(arg_id_value.name);
-
-      auto specs = value.repl.specs;
-
-      handle_dynamic_spec<width_checker>(specs.width, specs.width_ref, ctx);
-      handle_dynamic_spec<precision_checker>(specs.precision,
-                                             specs.precision_ref, ctx);
-
-      error_handler h;
-      numeric_specs_checker<error_handler> checker(h, arg.type());
-      if (specs.align == align::numeric) checker.require_numeric_argument();
-      if (specs.sign != sign::none) checker.check_sign();
-      if (specs.alt) checker.require_numeric_argument();
-      if (specs.precision >= 0) checker.check_precision();
-
-      advance_to(parse_ctx, part.arg_id_end);
-      ctx.advance_to(
-          visit_format_arg(arg_formatter<OutputIt, typename Context::char_type>(
-                               ctx, nullptr, &specs),
-                           arg));
-      break;
-    }
-    }
+  value_type& operator*() const {
+    return this->count_ < this->limit_ ? *this->out_ : blackhole_;
   }
-  return ctx.out();
-}
-}  // namespace cf
-
-struct basic_compiled_format {};
+};
 
-template <typename S, typename = void>
-struct compiled_format_base : basic_compiled_format {
-  using char_type = char_t<S>;
-  using parts_container = std::vector<detail::format_part<char_type>>;
+template <typename OutputIt>
+class truncating_iterator<OutputIt, std::true_type>
+    : public truncating_iterator_base<OutputIt> {
+ public:
+  truncating_iterator() = default;
 
-  parts_container compiled_parts;
+  truncating_iterator(OutputIt out, size_t limit)
+      : truncating_iterator_base<OutputIt>(out, limit) {}
 
-  explicit compiled_format_base(basic_string_view<char_type> format_str) {
-    compile_format_string<false>(format_str,
-                                 [this](const format_part<char_type>& part) {
-                                   compiled_parts.push_back(part);
-                                 });
+  template <typename T> truncating_iterator& operator=(T val) {
+    if (this->count_++ < this->limit_) *this->out_++ = val;
+    return *this;
   }
 
-  const parts_container& parts() const { return compiled_parts; }
-};
-
-template <typename Char, unsigned N> struct format_part_array {
-  format_part<Char> data[N] = {};
-  FMT_CONSTEXPR format_part_array() = default;
+  truncating_iterator& operator++() { return *this; }
+  truncating_iterator& operator++(int) { return *this; }
+  truncating_iterator& operator*() { return *this; }
 };
 
-template <typename Char, unsigned N>
-FMT_CONSTEXPR format_part_array<Char, N> compile_to_parts(
-    basic_string_view<Char> format_str) {
-  format_part_array<Char, N> parts;
-  unsigned counter = 0;
-  // This is not a lambda for compatibility with older compilers.
-  struct {
-    format_part<Char>* parts;
-    unsigned* counter;
-    FMT_CONSTEXPR void operator()(const format_part<Char>& part) {
-      parts[(*counter)++] = part;
-    }
-  } collector{parts.data, &counter};
-  compile_format_string<true>(format_str, collector);
-  if (counter < N) {
-    parts.data[counter] =
-        format_part<Char>::make_text(basic_string_view<Char>());
-  }
-  return parts;
-}
-
-template <typename T> constexpr const T& constexpr_max(const T& a, const T& b) {
-  return (a < b) ? b : a;
-}
+// A compile-time string which is compiled into fast formatting code.
+class compiled_string {};
 
 template <typename S>
-struct compiled_format_base<S, enable_if_t<is_compile_string<S>::value>>
-    : basic_compiled_format {
-  using char_type = char_t<S>;
+struct is_compiled_string : std::is_base_of<compiled_string, S> {};
 
-  FMT_CONSTEXPR explicit compiled_format_base(basic_string_view<char_type>) {}
+/**
+  \rst
+  Converts a string literal *s* into a format string that will be parsed at
+  compile time and converted into efficient formatting code. Requires C++17
+  ``constexpr if`` compiler support.
 
-// Workaround for old compilers. Format string compilation will not be
-// performed there anyway.
-#if FMT_USE_CONSTEXPR
-  static FMT_CONSTEXPR_DECL const unsigned num_format_parts =
-      constexpr_max(count_parts(to_string_view(S())), 1u);
+  **Example**::
+
+    // Converts 42 into std::string using the most efficient method and no
+    // runtime format string processing.
+    std::string s = fmt::format(FMT_COMPILE("{}"), 42);
+  \endrst
+ */
+#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
+#  define FMT_COMPILE(s) \
+    FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
 #else
-  static const unsigned num_format_parts = 1;
+#  define FMT_COMPILE(s) FMT_STRING(s)
 #endif
 
-  using parts_container = format_part<char_type>[num_format_parts];
-
-  const parts_container& parts() const {
-    static FMT_CONSTEXPR_DECL const auto compiled_parts =
-        compile_to_parts<char_type, num_format_parts>(
-            detail::to_string_view(S()));
-    return compiled_parts.data;
+#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
+template <typename Char, size_t N,
+          fmt::detail_exported::fixed_string<Char, N> Str>
+struct udl_compiled_string : compiled_string {
+  using char_type = Char;
+  constexpr operator basic_string_view<char_type>() const {
+    return {Str.data, N - 1};
   }
 };
+#endif
 
-template <typename S, typename... Args>
-class compiled_format : private compiled_format_base<S> {
- public:
-  using typename compiled_format_base<S>::char_type;
-
- private:
-  basic_string_view<char_type> format_str_;
-
-  template <typename Context, typename OutputIt, typename CompiledFormat>
-  friend auto cf::vformat_to(OutputIt out, CompiledFormat& cf,
-                             basic_format_args<Context> args) ->
-      typename Context::iterator;
-
- public:
-  compiled_format() = delete;
-  explicit constexpr compiled_format(basic_string_view<char_type> format_str)
-      : compiled_format_base<S>(format_str), format_str_(format_str) {}
-};
+template <typename T, typename... Tail>
+const T& first(const T& value, const Tail&...) {
+  return value;
+}
 
-#ifdef __cpp_if_constexpr
+#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
 template <typename... Args> struct type_list {};
 
 // Returns a reference to the argument at index N from [first, rest...].
@@ -374,13 +190,20 @@ constexpr const auto& get([[maybe_unused]] const T& first,
   if constexpr (N == 0)
     return first;
   else
-    return get<N - 1>(rest...);
+    return detail::get<N - 1>(rest...);
+}
+
+template <typename Char, typename... Args>
+constexpr int get_arg_index_by_name(basic_string_view<Char> name,
+                                    type_list<Args...>) {
+  return get_arg_index_by_name<Args...>(name);
 }
 
 template <int N, typename> struct get_type_impl;
 
 template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
-  using type = remove_cvref_t<decltype(get<N>(std::declval<Args>()...))>;
+  using type =
+      remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>;
 };
 
 template <int N, typename T>
@@ -393,7 +216,7 @@ template <typename Char> struct text {
   using char_type = Char;
 
   template <typename OutputIt, typename... Args>
-  OutputIt format(OutputIt out, const Args&...) const {
+  constexpr OutputIt format(OutputIt out, const Args&...) const {
     return write<Char>(out, data);
   }
 };
@@ -412,11 +235,22 @@ template <typename Char> struct code_unit {
   using char_type = Char;
 
   template <typename OutputIt, typename... Args>
-  OutputIt format(OutputIt out, const Args&...) const {
+  constexpr OutputIt format(OutputIt out, const Args&...) const {
     return write<Char>(out, value);
   }
 };
 
+// This ensures that the argument type is convertible to `const T&`.
+template <typename T, int N, typename... Args>
+constexpr const T& get_arg_checked(const Args&... args) {
+  const auto& arg = detail::get<N>(args...);
+  if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
+    return arg.value;
+  } else {
+    return arg;
+  }
+}
+
 template <typename Char>
 struct is_compiled_format<code_unit<Char>> : std::true_type {};
 
@@ -425,29 +259,58 @@ template <typename Char, typename T, int N> struct field {
   using char_type = Char;
 
   template <typename OutputIt, typename... Args>
-  OutputIt format(OutputIt out, const Args&... args) const {
-    // This ensures that the argument type is convertile to `const T&`.
-    const T& arg = get<N>(args...);
-    return write<Char>(out, arg);
+  constexpr OutputIt format(OutputIt out, const Args&... args) const {
+    return write<Char>(out, get_arg_checked<T, N>(args...));
   }
 };
 
 template <typename Char, typename T, int N>
 struct is_compiled_format<field<Char, T, N>> : std::true_type {};
 
+// A replacement field that refers to argument with name.
+template <typename Char> struct runtime_named_field {
+  using char_type = Char;
+  basic_string_view<Char> name;
+
+  template <typename OutputIt, typename T>
+  constexpr static bool try_format_argument(
+      OutputIt& out,
+      // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
+      [[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) {
+    if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) {
+      if (arg_name == arg.name) {
+        out = write<Char>(out, arg.value);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  template <typename OutputIt, typename... Args>
+  constexpr OutputIt format(OutputIt out, const Args&... args) const {
+    bool found = (try_format_argument(out, name, args) || ...);
+    if (!found) {
+      FMT_THROW(format_error("argument with specified name is not found"));
+    }
+    return out;
+  }
+};
+
+template <typename Char>
+struct is_compiled_format<runtime_named_field<Char>> : std::true_type {};
+
 // A replacement field that refers to argument N and has format specifiers.
 template <typename Char, typename T, int N> struct spec_field {
   using char_type = Char;
-  mutable formatter<T, Char> fmt;
+  formatter<T, Char> fmt;
 
   template <typename OutputIt, typename... Args>
-  OutputIt format(OutputIt out, const Args&... args) const {
-    // This ensures that the argument type is convertile to `const T&`.
-    const T& arg = get<N>(args...);
+  constexpr FMT_INLINE OutputIt format(OutputIt out,
+                                       const Args&... args) const {
     const auto& vargs =
-        make_format_args<basic_format_context<OutputIt, Char>>(args...);
+        fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...);
     basic_format_context<OutputIt, Char> ctx(out, vargs);
-    return fmt.format(arg, ctx);
+    return fmt.format(get_arg_checked<T, N>(args...), ctx);
   }
 };
 
@@ -460,7 +323,7 @@ template <typename L, typename R> struct concat {
   using char_type = typename L::char_type;
 
   template <typename OutputIt, typename... Args>
-  OutputIt format(OutputIt out, const Args&... args) const {
+  constexpr OutputIt format(OutputIt out, const Args&... args) const {
     out = lhs.format(out, args...);
     return rhs.format(out, args...);
   }
@@ -508,14 +371,79 @@ template <typename T, typename Char> struct parse_specs_result {
   int next_arg_id;
 };
 
+constexpr int manual_indexing_id = -1;
+
 template <typename T, typename Char>
 constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
-                                                  size_t pos, int arg_id) {
+                                                  size_t pos, int next_arg_id) {
   str.remove_prefix(pos);
-  auto ctx = basic_format_parse_context<Char>(str, {}, arg_id + 1);
+  auto ctx = basic_format_parse_context<Char>(str, {}, next_arg_id);
   auto f = formatter<T, Char>();
   auto end = f.parse(ctx);
-  return {f, pos + (end - str.data()) + 1, ctx.next_arg_id()};
+  return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1,
+          next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
+}
+
+template <typename Char> struct arg_id_handler {
+  arg_ref<Char> arg_id;
+
+  constexpr int operator()() {
+    FMT_ASSERT(false, "handler cannot be used with automatic indexing");
+    return 0;
+  }
+  constexpr int operator()(int id) {
+    arg_id = arg_ref<Char>(id);
+    return 0;
+  }
+  constexpr int operator()(basic_string_view<Char> id) {
+    arg_id = arg_ref<Char>(id);
+    return 0;
+  }
+
+  constexpr void on_error(const char* message) {
+    FMT_THROW(format_error(message));
+  }
+};
+
+template <typename Char> struct parse_arg_id_result {
+  arg_ref<Char> arg_id;
+  const Char* arg_id_end;
+};
+
+template <int ID, typename Char>
+constexpr auto parse_arg_id(const Char* begin, const Char* end) {
+  auto handler = arg_id_handler<Char>{arg_ref<Char>{}};
+  auto arg_id_end = parse_arg_id(begin, end, handler);
+  return parse_arg_id_result<Char>{handler.arg_id, arg_id_end};
+}
+
+template <typename T, typename Enable = void> struct field_type {
+  using type = remove_cvref_t<T>;
+};
+
+template <typename T>
+struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> {
+  using type = remove_cvref_t<decltype(T::value)>;
+};
+
+template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID,
+          typename S>
+constexpr auto parse_replacement_field_then_tail(S format_str) {
+  using char_type = typename S::char_type;
+  constexpr auto str = basic_string_view<char_type>(format_str);
+  constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type();
+  if constexpr (c == '}') {
+    return parse_tail<Args, END_POS + 1, NEXT_ID>(
+        field<char_type, typename field_type<T>::type, ARG_INDEX>(),
+        format_str);
+  } else if constexpr (c == ':') {
+    constexpr auto result = parse_specs<typename field_type<T>::type>(
+        str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
+    return parse_tail<Args, result.end, result.next_arg_id>(
+        spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
+            result.fmt},
+        format_str);
+  }
 }
 
 // Compiles a non-empty format string and returns the compiled representation
@@ -523,27 +451,59 @@ constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
 template <typename Args, size_t POS, int ID, typename S>
 constexpr auto compile_format_string(S format_str) {
   using char_type = typename S::char_type;
-  constexpr basic_string_view<char_type> str = format_str;
+  constexpr auto str = basic_string_view<char_type>(format_str);
   if constexpr (str[POS] == '{') {
-    if (POS + 1 == str.size())
-      throw format_error("unmatched '{' in format string");
+    if constexpr (POS + 1 == str.size())
+      FMT_THROW(format_error("unmatched '{' in format string"));
     if constexpr (str[POS + 1] == '{') {
       return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
-    } else if constexpr (str[POS + 1] == '}') {
-      using type = get_type<ID, Args>;
-      return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
-                                               format_str);
-    } else if constexpr (str[POS + 1] == ':') {
-      using type = get_type<ID, Args>;
-      constexpr auto result = parse_specs<type>(str, POS + 2, ID);
-      return parse_tail<Args, result.end, result.next_arg_id>(
-          spec_field<char_type, type, ID>{result.fmt}, format_str);
+    } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') {
+      static_assert(ID != manual_indexing_id,
+                    "cannot switch from manual to automatic argument indexing");
+      constexpr auto next_id =
+          ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
+      return parse_replacement_field_then_tail<get_type<ID, Args>, Args,
+                                               POS + 1, ID, next_id>(
+          format_str);
     } else {
-      return unknown_format();
+      constexpr auto arg_id_result =
+          parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size());
+      constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data();
+      constexpr char_type c =
+          arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
+      static_assert(c == '}' || c == ':', "missing '}' in format string");
+      if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) {
+        static_assert(
+            ID == manual_indexing_id || ID == 0,
+            "cannot switch from automatic to manual argument indexing");
+        constexpr auto arg_index = arg_id_result.arg_id.val.index;
+        return parse_replacement_field_then_tail<get_type<arg_index, Args>,
+                                                 Args, arg_id_end_pos,
+                                                 arg_index, manual_indexing_id>(
+            format_str);
+      } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) {
+        constexpr auto arg_index =
+            get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{});
+        if constexpr (arg_index != invalid_arg_index) {
+          constexpr auto next_id =
+              ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
+          return parse_replacement_field_then_tail<
+              decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos,
+              arg_index, next_id>(format_str);
+        } else {
+          if constexpr (c == '}') {
+            return parse_tail<Args, arg_id_end_pos + 1, ID>(
+                runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
+                format_str);
+          } else if constexpr (c == ':') {
+            return unknown_format();  // no type info for specs parsing
+          }
+        }
+      }
     }
   } else if constexpr (str[POS] == '}') {
-    if (POS + 1 == str.size())
-      throw format_error("unmatched '}' in format string");
+    if constexpr (POS + 1 == str.size())
+      FMT_THROW(format_error("unmatched '}' in format string"));
     return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
   } else {
     constexpr auto end = parse_text(str, POS + 1);
@@ -558,144 +518,125 @@ constexpr auto compile_format_string(S format_str) {
 }
 
 template <typename... Args, typename S,
-          FMT_ENABLE_IF(is_compile_string<S>::value ||
-                        detail::is_compiled_string<S>::value)>
+          FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
 constexpr auto compile(S format_str) {
-  constexpr basic_string_view<typename S::char_type> str = format_str;
+  constexpr auto str = basic_string_view<typename S::char_type>(format_str);
   if constexpr (str.size() == 0) {
     return detail::make_text(str, 0, 0);
   } else {
     constexpr auto result =
         detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
             format_str);
-    if constexpr (std::is_same<remove_cvref_t<decltype(result)>,
-                               detail::unknown_format>()) {
-      return detail::compiled_format<S, Args...>(to_string_view(format_str));
-    } else {
-      return result;
-    }
+    return result;
   }
 }
-#else
-template <typename... Args, typename S,
-          FMT_ENABLE_IF(is_compile_string<S>::value)>
-constexpr auto compile(S format_str) -> detail::compiled_format<S, Args...> {
-  return detail::compiled_format<S, Args...>(to_string_view(format_str));
-}
-#endif  // __cpp_if_constexpr
-
-// Compiles the format string which must be a string literal.
-template <typename... Args, typename Char, size_t N>
-auto compile(const Char (&format_str)[N])
-    -> detail::compiled_format<const Char*, Args...> {
-  return detail::compiled_format<const Char*, Args...>(
-      basic_string_view<Char>(format_str, N - 1));
-}
+#endif  // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
 }  // namespace detail
 
-// DEPRECATED! use FMT_COMPILE instead.
-template <typename... Args>
-FMT_DEPRECATED auto compile(const Args&... args)
-    -> decltype(detail::compile(args...)) {
-  return detail::compile(args...);
-}
+FMT_MODULE_EXPORT_BEGIN
 
-#if FMT_USE_CONSTEXPR
-#  ifdef __cpp_if_constexpr
+#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
 
 template <typename CompiledFormat, typename... Args,
           typename Char = typename CompiledFormat::char_type,
           FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
 FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
                                           const Args&... args) {
-  basic_memory_buffer<Char> buffer;
-  cf.format(detail::buffer_appender<Char>(buffer), args...);
-  return to_string(buffer);
+  auto s = std::basic_string<Char>();
+  cf.format(std::back_inserter(s), args...);
+  return s;
 }
 
 template <typename OutputIt, typename CompiledFormat, typename... Args,
           FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
-OutputIt format_to(OutputIt out, const CompiledFormat& cf,
-                   const Args&... args) {
+constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
+                                        const Args&... args) {
   return cf.format(out, args...);
 }
-#  endif  // __cpp_if_constexpr
-#endif    // FMT_USE_CONSTEXPR
-
-template <typename CompiledFormat, typename... Args,
-          typename Char = typename CompiledFormat::char_type,
-          FMT_ENABLE_IF(std::is_base_of<detail::basic_compiled_format,
-                                        CompiledFormat>::value)>
-std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
-  basic_memory_buffer<Char> buffer;
-  using context = buffer_context<Char>;
-  detail::cf::vformat_to<context>(detail::buffer_appender<Char>(buffer), cf,
-                                  make_format_args<context>(args...));
-  return to_string(buffer);
-}
 
 template <typename S, typename... Args,
           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
 FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
                                                            Args&&... args) {
-#ifdef __cpp_if_constexpr
   if constexpr (std::is_same<typename S::char_type, char>::value) {
-    constexpr basic_string_view<typename S::char_type> str = S();
-    if (str.size() == 2 && str[0] == '{' && str[1] == '}')
-      return fmt::to_string(detail::first(args...));
+    constexpr auto str = basic_string_view<typename S::char_type>(S());
+    if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
+      const auto& first = detail::first(args...);
+      if constexpr (detail::is_named_arg<
+                        remove_cvref_t<decltype(first)>>::value) {
+        return fmt::to_string(first.value);
+      } else {
+        return fmt::to_string(first);
+      }
+    }
   }
-#endif
   constexpr auto compiled = detail::compile<Args...>(S());
-  return format(compiled, std::forward<Args>(args)...);
-}
-
-template <typename OutputIt, typename CompiledFormat, typename... Args,
-          FMT_ENABLE_IF(std::is_base_of<detail::basic_compiled_format,
-                                        CompiledFormat>::value)>
-OutputIt format_to(OutputIt out, const CompiledFormat& cf,
-                   const Args&... args) {
-  using char_type = typename CompiledFormat::char_type;
-  using context = format_context_t<OutputIt, char_type>;
-  return detail::cf::vformat_to<context>(out, cf,
-                                         make_format_args<context>(args...));
+  if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
+                             detail::unknown_format>()) {
+    return format(static_cast<basic_string_view<typename S::char_type>>(S()),
+                  std::forward<Args>(args)...);
+  } else {
+    return format(compiled, std::forward<Args>(args)...);
+  }
 }
 
 template <typename OutputIt, typename S, typename... Args,
           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
-OutputIt format_to(OutputIt out, const S&, const Args&... args) {
+FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
   constexpr auto compiled = detail::compile<Args...>(S());
-  return format_to(out, compiled, args...);
+  if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
+                             detail::unknown_format>()) {
+    return format_to(out,
+                     static_cast<basic_string_view<typename S::char_type>>(S()),
+                     std::forward<Args>(args)...);
+  } else {
+    return format_to(out, compiled, std::forward<Args>(args)...);
+  }
 }
+#endif
 
-template <typename OutputIt, typename CompiledFormat, typename... Args>
-auto format_to_n(OutputIt out, size_t n, const CompiledFormat& cf,
-                 const Args&... args) ->
-    typename std::enable_if<
-        detail::is_output_iterator<OutputIt,
-                                   typename CompiledFormat::char_type>::value &&
-            std::is_base_of<detail::basic_compiled_format,
-                            CompiledFormat>::value,
-        format_to_n_result<OutputIt>>::type {
-  auto it =
-      format_to(detail::truncating_iterator<OutputIt>(out, n), cf, args...);
+template <typename OutputIt, typename S, typename... Args,
+          FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
+format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
+                                         const S& format_str, Args&&... args) {
+  auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), format_str,
+                      std::forward<Args>(args)...);
   return {it.base(), it.count()};
 }
 
-template <typename OutputIt, typename S, typename... Args,
+template <typename S, typename... Args,
           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
-format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, const S&,
-                                         const Args&... args) {
-  constexpr auto compiled = detail::compile<Args...>(S());
-  auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), compiled,
-                      args...);
-  return {it.base(), it.count()};
+size_t formatted_size(const S& format_str, const Args&... args) {
+  return format_to(detail::counting_iterator(), format_str, args...).count();
 }
 
-template <typename CompiledFormat, typename... Args>
-size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
-  return format_to(detail::counting_iterator(), cf, args...).count();
+template <typename S, typename... Args,
+          FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
+void print(std::FILE* f, const S& format_str, const Args&... args) {
+  memory_buffer buffer;
+  format_to(std::back_inserter(buffer), format_str, args...);
+  detail::print(f, {buffer.data(), buffer.size()});
 }
 
+template <typename S, typename... Args,
+          FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
+void print(const S& format_str, const Args&... args) {
+  print(stdout, format_str, args...);
+}
+
+#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
+inline namespace literals {
+template <detail_exported::fixed_string Str>
+constexpr detail::udl_compiled_string<
+    remove_cvref_t<decltype(Str.data[0])>,
+    sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str>
+operator""_cf() {
+  return {};
+}
+}  // namespace literals
+#endif
+
+FMT_MODULE_EXPORT_END
 FMT_END_NAMESPACE
 
 #endif  // FMT_COMPILE_H_

File diff suppressed because it is too large
+ 377 - 209
contrib/libs/fmt/include/fmt/core.h


Some files were not shown because too many files changed in this diff