]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Upgrade to fmt 6.2.0
authorJoel Rosdahl <joel@rosdahl.net>
Tue, 14 Apr 2020 19:05:39 +0000 (21:05 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Tue, 14 Apr 2020 19:05:39 +0000 (21:05 +0200)
LICENSE.adoc
src/third_party/fmt/core.h
src/third_party/fmt/format-inl.h
src/third_party/fmt/format.h
src/third_party/format.cpp

index dfd183b5ecdf47c0b7a739ddc576677f7f70ef01..e757d977ac205f847cd0c7ddceb8ab8d520cdd30 100644 (file)
@@ -55,7 +55,7 @@ under less restrictive terms.
 src/third_party/fmt/*.h and src/third_party/format.cpp
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-This is a subset of https://fmt.dev[fmt] 6.1.2 with the following license:
+This is a subset of https://fmt.dev[fmt] 6.2.0 with the following license:
 
 -------------------------------------------------------------------------------
   Formatting library for C++
index 9fd8df287851e5b2a782d31356eeda5323892174..6df2875acfc2ab4000e89e44a9badbecdcdc7e1b 100644 (file)
 
 #include <cstdio>  // std::FILE
 #include <cstring>
+#include <functional>
 #include <iterator>
+#include <memory>
 #include <string>
 #include <type_traits>
+#include <vector>
 
 // The fmt library version in the form major * 10000 + minor * 100 + patch.
-#define FMT_VERSION 60102
+#define FMT_VERSION 60200
 
 #ifdef __has_feature
 #  define FMT_HAS_FEATURE(x) __has_feature(x)
 #  define FMT_HAS_CPP_ATTRIBUTE(x) 0
 #endif
 
+#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
+  (__cplusplus >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
+
+#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
+  (__cplusplus >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
+
+#ifdef __clang__
+#  define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
+#else
+#  define FMT_CLANG_VERSION 0
+#endif
+
 #if defined(__GNUC__) && !defined(__clang__)
 #  define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
 #else
 #  endif
 #endif
 
-// [[noreturn]] is disabled on MSVC because of bogus unreachable code warnings.
-#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER
+// [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code
+// warnings.
+#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \
+    !FMT_NVCC
 #  define FMT_NORETURN [[noreturn]]
 #else
 #  define FMT_NORETURN
 #endif
 
+#ifndef FMT_MAYBE_UNUSED
+#  if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused)
+#    define FMT_MAYBE_UNUSED [[maybe_unused]]
+#  else
+#    define FMT_MAYBE_UNUSED
+#  endif
+#endif
+
 #ifndef FMT_DEPRECATED
-#  if (FMT_HAS_CPP_ATTRIBUTE(deprecated) && __cplusplus >= 201402L) || \
-      FMT_MSC_VER >= 1900
+#  if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900
 #    define FMT_DEPRECATED [[deprecated]]
 #  else
 #    if defined(__GNUC__) || defined(__clang__)
 #  endif
 #endif
 
-// Workaround broken [[deprecated]] in the Intel compiler and NVCC.
-#if defined(__INTEL_COMPILER) || FMT_NVCC
+// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers.
+#if defined(__INTEL_COMPILER) || defined(__PGI) || FMT_NVCC
 #  define FMT_DEPRECATED_ALIAS
 #else
 #  define FMT_DEPRECATED_ALIAS FMT_DEPRECATED
 #endif
 
 #if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
+#  if FMT_MSC_VER
+#    define FMT_NO_W4275 __pragma(warning(suppress : 4275))
+#  else
+#    define FMT_NO_W4275
+#  endif
+#  define FMT_CLASS_API FMT_NO_W4275
 #  ifdef FMT_EXPORT
 #    define FMT_API __declspec(dllexport)
 #  elif defined(FMT_SHARED)
 #    define FMT_EXTERN_TEMPLATE_API FMT_API
 #  endif
 #endif
+#ifndef FMT_CLASS_API
+#  define FMT_CLASS_API
+#endif
 #ifndef FMT_API
-#  define FMT_API
+#  if FMT_GCC_VERSION || FMT_CLANG_VERSION
+#    define FMT_API __attribute__((visibility("default")))
+#    define FMT_EXTERN_TEMPLATE_API FMT_API
+#    define FMT_INSTANTIATION_DEF_API
+#  else
+#    define FMT_API
+#  endif
 #endif
 #ifndef FMT_EXTERN_TEMPLATE_API
 #  define FMT_EXTERN_TEMPLATE_API
 #endif
+#ifndef FMT_INSTANTIATION_DEF_API
+#  define FMT_INSTANTIATION_DEF_API FMT_API
+#endif
 
 #ifndef FMT_HEADER_ONLY
 #  define FMT_EXTERN extern
 #  define FMT_USE_EXPERIMENTAL_STRING_VIEW
 #endif
 
+#ifndef FMT_UNICODE
+#  define FMT_UNICODE !FMT_MSC_VER
+#endif
+#if FMT_UNICODE && FMT_MSC_VER
+#  pragma execution_character_set("utf-8")
+#endif
+
 FMT_BEGIN_NAMESPACE
 
-// Implementations of enable_if_t and other types for pre-C++14 systems.
+// Implementations of enable_if_t and other metafunctions for older systems.
 template <bool B, class T = void>
 using enable_if_t = typename std::enable_if<B, T>::type;
 template <bool B, class T, class F>
@@ -211,6 +260,8 @@ template <typename T>
 using remove_const_t = typename std::remove_const<T>::type;
 template <typename T>
 using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
+template <typename T> struct type_identity { using type = T; };
+template <typename T> using type_identity_t = typename type_identity<T>::type;
 
 struct monostate {};
 
@@ -221,19 +272,25 @@ struct monostate {};
 
 namespace internal {
 
+// A helper function to suppress bogus "conditional expression is constant"
+// warnings.
+template <typename T> FMT_CONSTEXPR T const_check(T value) { return value; }
+
 // A workaround for gcc 4.8 to make void_t work in a SFINAE context.
 template <typename... Ts> struct void_t_impl { using type = void; };
 
-FMT_API void assert_fail(const char* file, int line, const char* message);
+FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
+                                      const char* message);
 
 #ifndef FMT_ASSERT
 #  ifdef NDEBUG
-#    define FMT_ASSERT(condition, message)
+// FMT_ASSERT is not empty to avoid -Werror=empty-body.
+#    define FMT_ASSERT(condition, message) ((void)0)
 #  else
-#    define FMT_ASSERT(condition, message) \
-      ((condition)                         \
-           ? void()                        \
-           : fmt::internal::assert_fail(__FILE__, __LINE__, (message)))
+#    define FMT_ASSERT(condition, message)                                    \
+      ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
+           ? (void)0                                                          \
+           : ::fmt::internal::assert_fail(__FILE__, __LINE__, (message)))
 #  endif
 #endif
 
@@ -248,7 +305,7 @@ template <typename T> struct std_string_view {};
 
 #ifdef FMT_USE_INT128
 // Do nothing.
-#elif defined(__SIZEOF_INT128__)
+#elif defined(__SIZEOF_INT128__) && !FMT_NVCC
 #  define FMT_USE_INT128 1
 using int128_t = __int128_t;
 using uint128_t = __uint128_t;
@@ -266,6 +323,19 @@ FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
   FMT_ASSERT(value >= 0, "negative value");
   return static_cast<typename std::make_unsigned<Int>::type>(value);
 }
+
+constexpr unsigned char micro[] = "\u00B5";
+
+template <typename Char> constexpr bool is_unicode() {
+  return FMT_UNICODE || sizeof(Char) != 1 ||
+         (sizeof(micro) == 3 && micro[0] == 0xC2 && micro[1] == 0xB5);
+}
+
+#ifdef __cpp_char8_t
+using char8_type = char8_t;
+#else
+enum char8_type : unsigned char {};
+#endif
 }  // namespace internal
 
 template <typename... Ts>
@@ -284,7 +354,8 @@ template <typename Char> class basic_string_view {
   size_t size_;
 
  public:
-  using char_type = Char;
+  using char_type FMT_DEPRECATED_ALIAS = Char;
+  using value_type = Char;
   using iterator = const Char*;
 
   FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {}
@@ -300,6 +371,9 @@ template <typename Char> class basic_string_view {
     the size with ``std::char_traits<Char>::length``.
     \endrst
    */
+#if __cplusplus >= 201703L  // C++17's char_traits::length() is constexpr.
+  FMT_CONSTEXPR
+#endif
   basic_string_view(const Char* s)
       : data_(s), size_(std::char_traits<Char>::length(s)) {}
 
@@ -365,15 +439,15 @@ using string_view = basic_string_view<char>;
 using wstring_view = basic_string_view<wchar_t>;
 
 #ifndef __cpp_char8_t
-// A UTF-8 code unit type.
-enum char8_t : unsigned char {};
+// char8_t is deprecated; use char instead.
+using char8_t FMT_DEPRECATED_ALIAS = internal::char8_type;
 #endif
 
 /** Specifies if ``T`` is a character type. Can be specialized by users. */
 template <typename T> struct is_char : std::false_type {};
 template <> struct is_char<char> : std::true_type {};
 template <> struct is_char<wchar_t> : std::true_type {};
-template <> struct is_char<char8_t> : std::true_type {};
+template <> struct is_char<internal::char8_type> : std::true_type {};
 template <> struct is_char<char16_t> : std::true_type {};
 template <> struct is_char<char32_t> : std::true_type {};
 
@@ -442,7 +516,7 @@ struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> {
 template <typename S, typename = void> struct char_t_impl {};
 template <typename S> struct char_t_impl<S, enable_if_t<is_string<S>::value>> {
   using result = decltype(to_string_view(std::declval<S>()));
-  using type = typename result::char_type;
+  using type = typename result::value_type;
 };
 
 struct error_handler {
@@ -603,6 +677,9 @@ template <typename T> class buffer {
   T* begin() FMT_NOEXCEPT { return ptr_; }
   T* end() FMT_NOEXCEPT { return ptr_ + size_; }
 
+  const T* begin() const FMT_NOEXCEPT { return ptr_; }
+  const T* end() const FMT_NOEXCEPT { return ptr_ + size_; }
+
   /** Returns the size of this buffer. */
   std::size_t size() const FMT_NOEXCEPT { return size_; }
 
@@ -639,8 +716,10 @@ template <typename T> class buffer {
   /** Appends data to the end of the buffer. */
   template <typename U> void append(const U* begin, const U* end);
 
-  T& operator[](std::size_t index) { return ptr_[index]; }
-  const T& operator[](std::size_t index) const { return ptr_[index]; }
+  template <typename I> T& operator[](I index) { return ptr_[index]; }
+  template <typename I> const T& operator[](I index) const {
+    return ptr_[index];
+  }
 };
 
 // A container-backed buffer.
@@ -684,7 +763,7 @@ using has_fallback_formatter =
 template <typename Char> struct named_arg_base;
 template <typename T, typename Char> struct named_arg;
 
-enum type {
+enum class type {
   none_type,
   named_arg_type,
   // Integer types should go first,
@@ -710,11 +789,12 @@ enum type {
 
 // Maps core type T to the corresponding type enum constant.
 template <typename T, typename Char>
-struct type_constant : std::integral_constant<type, custom_type> {};
+struct type_constant : std::integral_constant<type, type::custom_type> {};
 
 #define FMT_TYPE_CONSTANT(Type, constant) \
   template <typename Char>                \
-  struct type_constant<Type, Char> : std::integral_constant<type, constant> {}
+  struct type_constant<Type, Char>        \
+      : std::integral_constant<type, type::constant> {}
 
 FMT_TYPE_CONSTANT(const named_arg_base<Char>&, named_arg_type);
 FMT_TYPE_CONSTANT(int, int_type);
@@ -733,13 +813,13 @@ FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
 FMT_TYPE_CONSTANT(const void*, pointer_type);
 
 FMT_CONSTEXPR bool is_integral_type(type t) {
-  FMT_ASSERT(t != named_arg_type, "invalid argument type");
-  return t > none_type && t <= last_integer_type;
+  FMT_ASSERT(t != type::named_arg_type, "invalid argument type");
+  return t > type::none_type && t <= type::last_integer_type;
 }
 
 FMT_CONSTEXPR bool is_arithmetic_type(type t) {
-  FMT_ASSERT(t != named_arg_type, "invalid argument type");
-  return t > none_type && t <= last_numeric_type;
+  FMT_ASSERT(t != type::named_arg_type, "invalid argument type");
+  return t > type::none_type && t <= type::last_numeric_type;
 }
 
 template <typename Char> struct string_value {
@@ -869,7 +949,8 @@ template <typename Context> struct arg_mapper {
   template <typename T,
             FMT_ENABLE_IF(
                 std::is_constructible<basic_string_view<char_type>, T>::value &&
-                !is_string<T>::value)>
+                !is_string<T>::value && !has_formatter<T, Context>::value &&
+                !has_fallback_formatter<T, Context>::value)>
   FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
     return basic_string_view<char_type>(val);
   }
@@ -878,7 +959,8 @@ template <typename Context> struct arg_mapper {
       FMT_ENABLE_IF(
           std::is_constructible<std_string_view<char_type>, T>::value &&
           !std::is_constructible<basic_string_view<char_type>, T>::value &&
-          !is_string<T>::value && !has_formatter<T, Context>::value)>
+          !is_string<T>::value && !has_formatter<T, Context>::value &&
+          !has_fallback_formatter<T, Context>::value)>
   FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
     return std_string_view<char_type>(val);
   }
@@ -907,18 +989,15 @@ template <typename Context> struct arg_mapper {
             FMT_ENABLE_IF(std::is_enum<T>::value &&
                           !has_formatter<T, Context>::value &&
                           !has_fallback_formatter<T, Context>::value)>
-  FMT_CONSTEXPR auto map(const T& val) -> decltype(
-      map(static_cast<typename std::underlying_type<T>::type>(val))) {
+  FMT_CONSTEXPR auto map(const T& val)
+      -> decltype(std::declval<arg_mapper>().map(
+          static_cast<typename std::underlying_type<T>::type>(val))) {
     return map(static_cast<typename std::underlying_type<T>::type>(val));
   }
-  template <
-      typename T,
-      FMT_ENABLE_IF(
-          !is_string<T>::value && !is_char<T>::value &&
-          !std::is_constructible<basic_string_view<char_type>, T>::value &&
-          (has_formatter<T, Context>::value ||
-           (has_fallback_formatter<T, Context>::value &&
-            !std::is_constructible<std_string_view<char_type>, T>::value)))>
+  template <typename T,
+            FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value &&
+                          (has_formatter<T, Context>::value ||
+                           has_fallback_formatter<T, Context>::value))>
   FMT_CONSTEXPR const T& map(const T& val) {
     return val;
   }
@@ -930,6 +1009,16 @@ template <typename Context> struct arg_mapper {
     std::memcpy(val.data, &arg, sizeof(arg));
     return val;
   }
+
+  int map(...) {
+    constexpr bool formattable = sizeof(Context) == 0;
+    static_assert(
+        formattable,
+        "Cannot format argument. To make type T formattable provide a "
+        "formatter<T> specialization: "
+        "https://fmt.dev/latest/api.html#formatting-user-defined-types");
+    return 0;
+  }
 };
 
 // A type constant after applying arg_mapper<Context>.
@@ -981,10 +1070,10 @@ template <typename Context> class basic_format_arg {
     internal::custom_value<Context> custom_;
   };
 
-  FMT_CONSTEXPR basic_format_arg() : type_(internal::none_type) {}
+  FMT_CONSTEXPR basic_format_arg() : type_(internal::type::none_type) {}
 
   FMT_CONSTEXPR explicit operator bool() const FMT_NOEXCEPT {
-    return type_ != internal::none_type;
+    return type_ != internal::type::none_type;
   }
 
   internal::type type() const { return type_; }
@@ -1006,47 +1095,47 @@ FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
     -> decltype(vis(0)) {
   using char_type = typename Context::char_type;
   switch (arg.type_) {
-  case internal::none_type:
+  case internal::type::none_type:
     break;
-  case internal::named_arg_type:
+  case internal::type::named_arg_type:
     FMT_ASSERT(false, "invalid argument type");
     break;
-  case internal::int_type:
+  case internal::type::int_type:
     return vis(arg.value_.int_value);
-  case internal::uint_type:
+  case internal::type::uint_type:
     return vis(arg.value_.uint_value);
-  case internal::long_long_type:
+  case internal::type::long_long_type:
     return vis(arg.value_.long_long_value);
-  case internal::ulong_long_type:
+  case internal::type::ulong_long_type:
     return vis(arg.value_.ulong_long_value);
 #if FMT_USE_INT128
-  case internal::int128_type:
+  case internal::type::int128_type:
     return vis(arg.value_.int128_value);
-  case internal::uint128_type:
+  case internal::type::uint128_type:
     return vis(arg.value_.uint128_value);
 #else
-  case internal::int128_type:
-  case internal::uint128_type:
+  case internal::type::int128_type:
+  case internal::type::uint128_type:
     break;
 #endif
-  case internal::bool_type:
+  case internal::type::bool_type:
     return vis(arg.value_.bool_value);
-  case internal::char_type:
+  case internal::type::char_type:
     return vis(arg.value_.char_value);
-  case internal::float_type:
+  case internal::type::float_type:
     return vis(arg.value_.float_value);
-  case internal::double_type:
+  case internal::type::double_type:
     return vis(arg.value_.double_value);
-  case internal::long_double_type:
+  case internal::type::long_double_type:
     return vis(arg.value_.long_double_value);
-  case internal::cstring_type:
+  case internal::type::cstring_type:
     return vis(arg.value_.string.data);
-  case internal::string_type:
+  case internal::type::string_type:
     return vis(basic_string_view<char_type>(arg.value_.string.data,
                                             arg.value_.string.size));
-  case internal::pointer_type:
+  case internal::type::pointer_type:
     return vis(arg.value_.pointer);
-  case internal::custom_type:
+  case internal::type::custom_type:
     return vis(typename basic_format_arg<Context>::handle(arg.value_.custom));
   }
   return vis(monostate());
@@ -1106,7 +1195,7 @@ template <typename> constexpr unsigned long long encode_types() { return 0; }
 
 template <typename Context, typename Arg, typename... Args>
 constexpr unsigned long long encode_types() {
-  return mapped_type_constant<Arg, Context>::value |
+  return static_cast<unsigned>(mapped_type_constant<Arg, Context>::value) |
          (encode_types<Context, Args...>() << packed_arg_bits);
 }
 
@@ -1129,6 +1218,43 @@ template <bool IS_PACKED, typename Context, typename T,
 inline basic_format_arg<Context> make_arg(const T& value) {
   return make_arg<Context>(value);
 }
+
+template <typename T> struct is_reference_wrapper : std::false_type {};
+
+template <typename T>
+struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
+
+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 node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
+    auto& value = node->value;
+    node->next = std::move(head_);
+    head_ = std::move(node);
+    return value;
+  }
+};
 }  // namespace internal
 
 // Formatting context.
@@ -1191,7 +1317,13 @@ using wformat_context = buffer_context<wchar_t>;
   such as `~fmt::vformat`.
   \endrst
  */
-template <typename Context, typename... Args> class format_arg_store {
+template <typename Context, typename... Args>
+class 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:
   static const size_t num_args = sizeof...(Args);
   static const bool is_packed = num_args < internal::max_packed_args;
@@ -1210,7 +1342,12 @@ template <typename Context, typename... Args> class format_arg_store {
                 : internal::is_unpacked_bit | num_args;
 
   format_arg_store(const Args&... args)
-      : data_{internal::make_arg<is_packed, Context>(args)...} {}
+      :
+#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
+        basic_format_args<Context>(*this),
+#endif
+        data_{internal::make_arg<is_packed, Context>(args)...} {
+  }
 };
 
 /**
@@ -1227,7 +1364,112 @@ inline format_arg_store<Context, Args...> make_format_args(
   return {args...};
 }
 
-/** Formatting arguments. */
+/**
+  \rst
+  A dynamic version of `fmt::format_arg_store<>`.
+  It's equipped with a storage to potentially temporary objects which lifetime
+  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 internal::type mapped_type =
+        internal::mapped_type_constant<T, Context>::value;
+
+    enum {
+      value = !(internal::is_reference_wrapper<T>::value ||
+                std::is_same<T, basic_string_view<char_type>>::value ||
+                std::is_same<T, internal::std_string_view<char_type>>::value ||
+                (mapped_type != internal::type::cstring_type &&
+                 mapped_type != internal::type::string_type &&
+                 mapped_type != internal::type::custom_type &&
+                 mapped_type != internal::type::named_arg_type))
+    };
+  };
+
+  template <typename T>
+  using stored_type = conditional_t<internal::is_string<T>::value,
+                                    std::basic_string<char_type>, T>;
+
+  // Storage of basic_format_arg must be contiguous.
+  std::vector<basic_format_arg<Context>> data_;
+
+  // Storage of arguments not fitting into basic_format_arg must grow
+  // without relocation because items in data_ refer to it.
+  internal::dynamic_arg_list dynamic_args_;
+
+  friend class basic_format_args<Context>;
+
+  unsigned long long get_types() const {
+    return internal::is_unpacked_bit | data_.size();
+  }
+
+  template <typename T> void emplace_arg(const T& arg) {
+    data_.emplace_back(internal::make_arg<Context>(arg));
+  }
+
+ public:
+  /**
+    \rst
+    Adds an argument into the dynamic store for later passing to a formating
+    function.
+
+    Note that custom types and string types (but not string views!) are copied
+    into the store with dynamic memory (in addition to resizing vector).
+
+    **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) {
+    static_assert(
+        !std::is_base_of<internal::named_arg_base<char_type>, T>::value,
+        "named arguments are not supported yet");
+    if (internal::const_check(need_copy<T>::value))
+      emplace_arg(dynamic_args_.push<stored_type<T>>(arg));
+    else
+      emplace_arg(arg);
+  }
+
+  /**
+    Adds a reference to the argument into the dynamic store for later passing to
+    a formating function.
+  */
+  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());
+  }
+};
+
+/**
+  \rst
+  A view of a collection of formatting arguments. To avoid lifetime issues it
+  should only be used as a parameter type in type-erased functions such as
+  ``vformat``::
+
+    void vlog(string_view format_str, format_args args);  // OK
+    format_args args = make_format_args(42);  // Error: dangling reference
+  \endrst
+ */
 template <typename Context> class basic_format_args {
  public:
   using size_type = int;
@@ -1269,7 +1511,7 @@ template <typename Context> class basic_format_args {
     }
     if (index > internal::max_packed_args) return arg;
     arg.type_ = type(index);
-    if (arg.type_ == internal::none_type) return arg;
+    if (arg.type_ == internal::type::none_type) return arg;
     internal::value<Context>& val = arg.value_;
     val = values_[index];
     return arg;
@@ -1289,6 +1531,17 @@ template <typename Context> class basic_format_args {
     set_data(store.data_);
   }
 
+  /**
+   \rst
+   Constructs a `basic_format_args` object from
+   `~fmt::dynamic_format_arg_store`.
+   \endrst
+   */
+  basic_format_args(const dynamic_format_arg_store<Context>& store)
+      : types_(store.get_types()) {
+    set_data(store.data_.data());
+  }
+
   /**
    \rst
    Constructs a `basic_format_args` object from a dynamic set of arguments.
@@ -1302,7 +1555,7 @@ template <typename Context> class basic_format_args {
   /** Returns the argument at specified index. */
   format_arg get(int index) const {
     format_arg arg = do_get(index);
-    if (arg.type_ == internal::named_arg_type)
+    if (arg.type_ == internal::type::named_arg_type)
       arg = arg.value_.named_arg->template deserialize<Context>();
     return arg;
   }
@@ -1319,12 +1572,12 @@ template <typename Context> class basic_format_args {
 struct format_args : basic_format_args<format_context> {
   template <typename... Args>
   format_args(Args&&... args)
-      : basic_format_args<format_context>(std::forward<Args>(args)...) {}
+      : basic_format_args<format_context>(static_cast<Args&&>(args)...) {}
 };
 struct wformat_args : basic_format_args<wformat_context> {
   template <typename... Args>
   wformat_args(Args&&... args)
-      : basic_format_args<wformat_context>(std::forward<Args>(args)...) {}
+      : basic_format_args<wformat_context>(static_cast<Args&&>(args)...) {}
 };
 
 template <typename Container> struct is_contiguous : std::false_type {};
@@ -1358,7 +1611,10 @@ template <typename Char> struct named_arg_base {
   }
 };
 
-template <typename T, typename Char> struct named_arg : named_arg_base<Char> {
+struct view {};
+
+template <typename T, typename Char>
+struct named_arg : view, named_arg_base<Char> {
   const T& value;
 
   named_arg(basic_string_view<Char> name, const T& val)
@@ -1376,7 +1632,6 @@ inline void check_format_string(const S&) {
 template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
 void check_format_string(S);
 
-struct view {};
 template <bool...> struct bool_pack;
 template <bool... Args>
 using all_true =
@@ -1386,32 +1641,38 @@ template <typename... Args, typename S, typename Char = char_t<S>>
 inline format_arg_store<buffer_context<Char>, remove_reference_t<Args>...>
 make_args_checked(const S& format_str,
                   const remove_reference_t<Args>&... args) {
-  static_assert(all_true<(!std::is_base_of<view, remove_reference_t<Args>>() ||
-                          !std::is_reference<Args>())...>::value,
-                "passing views as lvalues is disallowed");
-  check_format_string<remove_const_t<remove_reference_t<Args>>...>(format_str);
+  static_assert(
+      all_true<(!std::is_base_of<view, remove_reference_t<Args>>::value ||
+                !std::is_reference<Args>::value)...>::value,
+      "passing views as lvalues is disallowed");
+  check_format_string<Args...>(format_str);
   return {args...};
 }
 
 template <typename Char>
-std::basic_string<Char> vformat(basic_string_view<Char> format_str,
-                                basic_format_args<buffer_context<Char>> args);
+std::basic_string<Char> vformat(
+    basic_string_view<Char> format_str,
+    basic_format_args<buffer_context<type_identity_t<Char>>> args);
 
 template <typename Char>
 typename buffer_context<Char>::iterator vformat_to(
     buffer<Char>& buf, basic_string_view<Char> format_str,
-    basic_format_args<buffer_context<Char>> args);
+    basic_format_args<buffer_context<type_identity_t<Char>>> args);
+
+template <typename Char, typename Args,
+          FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
+inline void vprint_mojibake(std::FILE*, basic_string_view<Char>, const Args&) {}
+
+FMT_API void vprint_mojibake(std::FILE*, string_view, format_args);
+#ifndef _WIN32
+inline void vprint_mojibake(std::FILE*, string_view, format_args) {}
+#endif
 }  // namespace internal
 
 /**
   \rst
-  Returns a named argument to be used in a formatting function.
-
-  The named argument holds a reference and does not extend the lifetime
-  of its arguments.
-  Consequently, a dangling reference can accidentally be created.
-  The user should take care to only pass this function temporaries when
-  the named argument is itself a temporary, as per the following example.
+  Returns a named argument to be used in a formatting function. It should only
+  be used in a call to a formatting function.
 
   **Example**::
 
@@ -1434,8 +1695,9 @@ void arg(S, internal::named_arg<T, Char>) = delete;
 template <typename OutputIt, typename S, typename Char = char_t<S>,
           FMT_ENABLE_IF(
               internal::is_contiguous_back_insert_iterator<OutputIt>::value)>
-OutputIt vformat_to(OutputIt out, const S& format_str,
-                    basic_format_args<buffer_context<Char>> args) {
+OutputIt vformat_to(
+    OutputIt out, const S& format_str,
+    basic_format_args<buffer_context<type_identity_t<Char>>> args) {
   using container = remove_reference_t<decltype(internal::get_container(out))>;
   internal::container_buffer<container> buf((internal::get_container(out)));
   internal::vformat_to(buf, to_string_view(format_str), args);
@@ -1448,14 +1710,14 @@ template <typename Container, typename S, typename... Args,
 inline std::back_insert_iterator<Container> format_to(
     std::back_insert_iterator<Container> out, const S& format_str,
     Args&&... args) {
-  return vformat_to(
-      out, to_string_view(format_str),
-      {internal::make_args_checked<Args...>(format_str, args...)});
+  return vformat_to(out, to_string_view(format_str),
+                    internal::make_args_checked<Args...>(format_str, args...));
 }
 
 template <typename S, typename Char = char_t<S>>
 inline std::basic_string<Char> vformat(
-    const S& format_str, basic_format_args<buffer_context<Char>> args) {
+    const S& format_str,
+    basic_format_args<buffer_context<type_identity_t<Char>>> args) {
   return internal::vformat(to_string_view(format_str), args);
 }
 
@@ -1475,44 +1737,52 @@ template <typename S, typename... Args, typename Char = char_t<S>>
 inline std::basic_string<Char> format(const S& format_str, Args&&... args) {
   return internal::vformat(
       to_string_view(format_str),
-      {internal::make_args_checked<Args...>(format_str, args...)});
+      internal::make_args_checked<Args...>(format_str, args...));
 }
 
-FMT_API void vprint(std::FILE* f, string_view format_str, format_args args);
-FMT_API void vprint(string_view format_str, format_args args);
+FMT_API void vprint(string_view, format_args);
+FMT_API void vprint(std::FILE*, string_view, format_args);
 
 /**
   \rst
-  Prints formatted data to the file *f*. For wide format strings,
-  *f* should be in wide-oriented mode set via ``fwide(f, 1)`` or
-  ``_setmode(_fileno(f), _O_U8TEXT)`` on Windows.
+  Formats ``args`` according to specifications in ``format_str`` and writes the
+  output to the file ``f``. Strings are assumed to be Unicode-encoded unless the
+  ``FMT_UNICODE`` macro is set to 0.
 
   **Example**::
 
     fmt::print(stderr, "Don't {}!", "panic");
   \endrst
  */
-template <typename S, typename... Args,
-          FMT_ENABLE_IF(internal::is_string<S>::value)>
+template <typename S, typename... Args, typename Char = char_t<S>>
 inline void print(std::FILE* f, const S& format_str, Args&&... args) {
-  vprint(f, to_string_view(format_str),
-         internal::make_args_checked<Args...>(format_str, args...));
+  return internal::is_unicode<Char>()
+             ? vprint(f, to_string_view(format_str),
+                      internal::make_args_checked<Args...>(format_str, args...))
+             : internal::vprint_mojibake(
+                   f, to_string_view(format_str),
+                   internal::make_args_checked<Args...>(format_str, args...));
 }
 
 /**
   \rst
-  Prints formatted data to ``stdout``.
+  Formats ``args`` according to specifications in ``format_str`` and writes
+  the output to ``stdout``. Strings are assumed to be Unicode-encoded unless
+  the ``FMT_UNICODE`` macro is set to 0.
 
   **Example**::
 
     fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
   \endrst
  */
-template <typename S, typename... Args,
-          FMT_ENABLE_IF(internal::is_string<S>::value)>
+template <typename S, typename... Args, typename Char = char_t<S>>
 inline void print(const S& format_str, Args&&... args) {
-  vprint(to_string_view(format_str),
-         internal::make_args_checked<Args...>(format_str, args...));
+  return internal::is_unicode<Char>()
+             ? vprint(to_string_view(format_str),
+                      internal::make_args_checked<Args...>(format_str, args...))
+             : internal::vprint_mojibake(
+                   stdout, to_string_view(format_str),
+                   internal::make_args_checked<Args...>(format_str, args...));
 }
 FMT_END_NAMESPACE
 
index 72b304665df9246cebe800dd633ee118c0208c04..f632714d81e9ae9855a686f657bef1c861f9ea3c 100644 (file)
@@ -8,8 +8,6 @@
 #ifndef FMT_FORMAT_INL_H_
 #define FMT_FORMAT_INL_H_
 
-#include "format.h"
-
 #include <cassert>
 #include <cctype>
 #include <climits>
 #include <cstdarg>
 #include <cstring>  // for std::memmove
 #include <cwchar>
+
+#include "format.h"
 #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
 #  include <locale>
 #endif
 
-#if FMT_USE_WINDOWS_H
-#  if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
-#    define WIN32_LEAN_AND_MEAN
-#  endif
-#  if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
-#    include <windows.h>
-#  else
-#    define NOMINMAX
-#    include <windows.h>
-#    undef NOMINMAX
-#  endif
-#endif
-
-#if FMT_EXCEPTIONS
-#  define FMT_TRY try
-#  define FMT_CATCH(x) catch (x)
-#else
-#  define FMT_TRY if (true)
-#  define FMT_CATCH(x) if (false)
+#ifdef _WIN32
+#  include <io.h>
+#  include <windows.h>
 #endif
 
 #ifdef _MSC_VER
@@ -73,8 +57,6 @@ inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) {
 #  define FMT_SNPRINTF fmt_snprintf
 #endif  // _MSC_VER
 
-using format_func = void (*)(internal::buffer<char>&, int, string_view);
-
 // A portable thread-safe version of strerror.
 // Sets buffer to point to a string describing the error code.
 // This can be either a pointer to a string stored in buffer,
@@ -104,6 +86,7 @@ FMT_FUNC int safe_strerror(int error_code, char*& buffer,
     }
 
     // Handle the result of GNU-specific version of strerror_r.
+    FMT_MAYBE_UNUSED
     int handle(char* message) {
       // If the buffer is full then the message is probably truncated.
       if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
@@ -113,11 +96,13 @@ FMT_FUNC int safe_strerror(int error_code, char*& buffer,
     }
 
     // Handle the case when strerror_r is not available.
+    FMT_MAYBE_UNUSED
     int handle(internal::null<>) {
       return fallback(strerror_s(buffer_, buffer_size_, error_code_));
     }
 
     // Fallback to strerror_s when strerror_r is not available.
+    FMT_MAYBE_UNUSED
     int fallback(int result) {
       // If the buffer is full then the message is probably truncated.
       return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? ERANGE
@@ -168,15 +153,6 @@ FMT_FUNC void format_error_code(internal::buffer<char>& out, int error_code,
   assert(out.size() <= inline_buffer_size);
 }
 
-// A wrapper around fwrite that throws on error.
-FMT_FUNC void fwrite_fully(const void* ptr, size_t size, size_t count,
-                           FILE* stream) {
-  size_t written = std::fwrite(ptr, size, count, stream);
-  if (written < count) {
-    FMT_THROW(system_error(errno, "cannot write to file"));
-  }
-}
-
 FMT_FUNC void report_error(format_func func, int error_code,
                            string_view message) FMT_NOEXCEPT {
   memory_buffer full_message;
@@ -185,6 +161,13 @@ FMT_FUNC void report_error(format_func func, int error_code,
   (void)std::fwrite(full_message.data(), full_message.size(), 1, stderr);
   std::fputc('\n', stderr);
 }
+
+// A wrapper around fwrite that throws on error.
+FMT_FUNC void fwrite_fully(const void* ptr, size_t size, size_t count,
+                           FILE* stream) {
+  size_t written = std::fwrite(ptr, size, count, stream);
+  if (written < count) FMT_THROW(system_error(errno, "cannot write to file"));
+}
 }  // namespace internal
 
 #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
@@ -356,6 +339,10 @@ class fp {
  private:
   using significand_type = uint64_t;
 
+ public:
+  significand_type f;
+  int e;
+
   // All sizes are in bits.
   // Subtract 1 to account for an implicit most significant bit in the
   // normalized form.
@@ -363,11 +350,6 @@ class fp {
       std::numeric_limits<double>::digits - 1;
   static FMT_CONSTEXPR_DECL const uint64_t implicit_bit =
       1ULL << double_significand_size;
-
- public:
-  significand_type f;
-  int e;
-
   static FMT_CONSTEXPR_DECL const int significand_size =
       bits<significand_type>::value;
 
@@ -378,22 +360,6 @@ class fp {
   // errors on platforms where double is not IEEE754.
   template <typename Double> explicit fp(Double d) { assign(d); }
 
-  // Normalizes the value converted from double and multiplied by (1 << SHIFT).
-  template <int SHIFT> friend fp normalize(fp value) {
-    // Handle subnormals.
-    const auto shifted_implicit_bit = fp::implicit_bit << SHIFT;
-    while ((value.f & shifted_implicit_bit) == 0) {
-      value.f <<= 1;
-      --value.e;
-    }
-    // Subtract 1 to account for hidden bit.
-    const auto offset =
-        fp::significand_size - fp::double_significand_size - SHIFT - 1;
-    value.f <<= offset;
-    value.e -= offset;
-    return value;
-  }
-
   // Assigns d to this and return true iff predecessor is closer than successor.
   template <typename Double, FMT_ENABLE_IF(sizeof(Double) == sizeof(uint64_t))>
   bool assign(Double d) {
@@ -406,7 +372,8 @@ class fp {
     const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
     auto u = bit_cast<uint64_t>(d);
     f = u & significand_mask;
-    auto biased_e = (u & exponent_mask) >> double_significand_size;
+    int biased_e =
+        static_cast<int>((u & exponent_mask) >> double_significand_size);
     // Predecessor is closer if d is a normalized power of 2 (f == 0) other than
     // the smallest normalized number (biased_e > 1).
     bool is_predecessor_closer = f == 0 && biased_e > 1;
@@ -414,7 +381,7 @@ class fp {
       f += implicit_bit;
     else
       biased_e = 1;  // Subnormals use biased exponent 1 (min exponent).
-    e = static_cast<int>(biased_e - exponent_bias - double_significand_size);
+    e = biased_e - exponent_bias - double_significand_size;
     return is_predecessor_closer;
   }
 
@@ -453,6 +420,22 @@ class fp {
   }
 };
 
+// Normalizes the value converted from double and multiplied by (1 << SHIFT).
+template <int SHIFT> fp normalize(fp value) {
+  // Handle subnormals.
+  const auto shifted_implicit_bit = fp::implicit_bit << SHIFT;
+  while ((value.f & shifted_implicit_bit) == 0) {
+    value.f <<= 1;
+    --value.e;
+  }
+  // Subtract 1 to account for hidden bit.
+  const auto offset =
+      fp::significand_size - fp::double_significand_size - SHIFT - 1;
+  value.f <<= offset;
+  value.e -= offset;
+  return value;
+}
+
 inline bool operator==(fp x, fp y) { return x.f == y.f && x.e == y.e; }
 
 // Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking.
@@ -477,14 +460,12 @@ inline fp operator*(fp x, fp y) { return {multiply(x.f, y.f), x.e + y.e + 64}; }
 
 // Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its
 // (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`.
-FMT_FUNC fp get_cached_power(int min_exponent, int& pow10_exponent) {
-  const uint64_t one_over_log2_10 = 0x4d104d42;  // round(pow(2, 32) / log2(10))
+inline fp get_cached_power(int min_exponent, int& pow10_exponent) {
+  const int64_t one_over_log2_10 = 0x4d104d42;  // round(pow(2, 32) / log2(10))
   int index = static_cast<int>(
-      static_cast<int64_t>(
-          (min_exponent + fp::significand_size - 1) * one_over_log2_10 +
-          ((uint64_t(1) << 32) - 1)  // ceil
-          ) >>
-      32  // arithmetic shift
+      ((min_exponent + fp::significand_size - 1) * one_over_log2_10 +
+       ((int64_t(1) << 32) - 1))  // ceil
+      >> 32                       // arithmetic shift
   );
   // Decimal exponent of the first (smallest) cached power of 10.
   const int first_dec_exp = -348;
@@ -526,20 +507,23 @@ class bigint {
   basic_memory_buffer<bigit, bigits_capacity> bigits_;
   int exp_;
 
+  bigit operator[](int index) const { return bigits_[to_unsigned(index)]; }
+  bigit& operator[](int index) { return bigits_[to_unsigned(index)]; }
+
   static FMT_CONSTEXPR_DECL const int bigit_bits = bits<bigit>::value;
 
   friend struct formatter<bigint>;
 
   void subtract_bigits(int index, bigit other, bigit& borrow) {
-    auto result = static_cast<double_bigit>(bigits_[index]) - other - borrow;
-    bigits_[index] = static_cast<bigit>(result);
+    auto result = static_cast<double_bigit>((*this)[index]) - other - borrow;
+    (*this)[index] = static_cast<bigit>(result);
     borrow = static_cast<bigit>(result >> (bigit_bits * 2 - 1));
   }
 
   void remove_leading_zeros() {
     int num_bigits = static_cast<int>(bigits_.size()) - 1;
-    while (num_bigits > 0 && bigits_[num_bigits] == 0) --num_bigits;
-    bigits_.resize(num_bigits + 1);
+    while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits;
+    bigits_.resize(to_unsigned(num_bigits + 1));
   }
 
   // Computes *this -= other assuming aligned bigints and *this >= other.
@@ -548,8 +532,7 @@ class bigint {
     FMT_ASSERT(compare(*this, other) >= 0, "");
     bigit borrow = 0;
     int i = other.exp_ - exp_;
-    for (int j = 0, n = static_cast<int>(other.bigits_.size()); j != n;
-         ++i, ++j) {
+    for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j) {
       subtract_bigits(i, other.bigits_[j], borrow);
     }
     while (borrow > 0) subtract_bigits(i, 0, borrow);
@@ -600,7 +583,7 @@ class bigint {
   }
 
   void assign(uint64_t n) {
-    int num_bigits = 0;
+    size_t num_bigits = 0;
     do {
       bigits_[num_bigits++] = n & ~bigit(0);
       n >>= bigit_bits;
@@ -641,7 +624,7 @@ class bigint {
     int end = i - j;
     if (end < 0) end = 0;
     for (; i >= end; --i, --j) {
-      bigit lhs_bigit = lhs.bigits_[i], rhs_bigit = rhs.bigits_[j];
+      bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j];
       if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1;
     }
     if (i != j) return i > j ? 1 : -1;
@@ -656,7 +639,7 @@ class bigint {
     if (max_lhs_bigits + 1 < num_rhs_bigits) return -1;
     if (max_lhs_bigits > num_rhs_bigits) return 1;
     auto get_bigit = [](const bigint& n, int i) -> bigit {
-      return i >= n.exp_ && i < n.num_bigits() ? n.bigits_[i - n.exp_] : 0;
+      return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0;
     };
     double_bigit borrow = 0;
     int min_exp = (std::min)((std::min)(lhs1.exp_, lhs2.exp_), rhs.exp_);
@@ -696,7 +679,7 @@ class bigint {
     basic_memory_buffer<bigit, bigits_capacity> n(std::move(bigits_));
     int num_bigits = static_cast<int>(bigits_.size());
     int num_result_bigits = 2 * num_bigits;
-    bigits_.resize(num_result_bigits);
+    bigits_.resize(to_unsigned(num_result_bigits));
     using accumulator_t = conditional_t<FMT_USE_INT128, uint128_t, accumulator>;
     auto sum = accumulator_t();
     for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) {
@@ -706,7 +689,7 @@ class bigint {
         // Most terms are multiplied twice which can be optimized in the future.
         sum += static_cast<double_bigit>(n[i]) * n[j];
       }
-      bigits_[bigit_index] = static_cast<bigit>(sum);
+      (*this)[bigit_index] = static_cast<bigit>(sum);
       sum >>= bits<bigit>::value;  // Compute the carry.
     }
     // Do the same for the top half.
@@ -714,7 +697,7 @@ class bigint {
          ++bigit_index) {
       for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;)
         sum += static_cast<double_bigit>(n[i++]) * n[j--];
-      bigits_[bigit_index] = static_cast<bigit>(sum);
+      (*this)[bigit_index] = static_cast<bigit>(sum);
       sum >>= bits<bigit>::value;
     }
     --num_result_bigits;
@@ -728,11 +711,11 @@ class bigint {
     FMT_ASSERT(this != &divisor, "");
     if (compare(*this, divisor) < 0) return 0;
     int num_bigits = static_cast<int>(bigits_.size());
-    FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1] != 0, "");
+    FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, "");
     int exp_difference = exp_ - divisor.exp_;
     if (exp_difference > 0) {
       // Align bigints by adding trailing zeros to simplify subtraction.
-      bigits_.resize(num_bigits + exp_difference);
+      bigits_.resize(to_unsigned(num_bigits + exp_difference));
       for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j)
         bigits_[j] = bigits_[i];
       std::uninitialized_fill_n(bigits_.data(), exp_difference, 0);
@@ -747,7 +730,7 @@ class bigint {
   }
 };
 
-enum round_direction { unknown, up, down };
+enum class round_direction { unknown, up, down };
 
 // Given the divisor (normally a power of 10), the remainder = v % divisor for
 // some number v and the error, returns whether v should be rounded up, down, or
@@ -760,13 +743,13 @@ inline round_direction get_round_direction(uint64_t divisor, uint64_t remainder,
   FMT_ASSERT(error < divisor - error, "");  // error * 2 won't overflow.
   // Round down if (remainder + error) * 2 <= divisor.
   if (remainder <= divisor - remainder && error * 2 <= divisor - remainder * 2)
-    return down;
+    return round_direction::down;
   // Round up if (remainder - error) * 2 >= divisor.
   if (remainder >= error &&
       remainder - error >= divisor - (remainder - error)) {
-    return up;
+    return round_direction::up;
   }
-  return unknown;
+  return round_direction::unknown;
 }
 
 namespace digits {
@@ -777,6 +760,20 @@ enum result {
 };
 }
 
+// A version of count_digits optimized for grisu_gen_digits.
+inline int grisu_count_digits(uint32_t n) {
+  if (n < 10) return 1;
+  if (n < 100) return 2;
+  if (n < 1000) return 3;
+  if (n < 10000) return 4;
+  if (n < 100000) return 5;
+  if (n < 1000000) return 6;
+  if (n < 10000000) return 7;
+  if (n < 100000000) return 8;
+  if (n < 1000000000) return 9;
+  return 10;
+}
+
 // Generates output using the Grisu digit-gen algorithm.
 // error: the size of the region (lower, upper) outside of which numbers
 // definitely do not round to value (Delta in Grisu3).
@@ -792,7 +789,7 @@ FMT_ALWAYS_INLINE digits::result grisu_gen_digits(fp value, uint64_t error,
   FMT_ASSERT(integral == value.f >> -one.e, "");
   // The fractional part of scaled value (p2 in Grisu) c = value % one.
   uint64_t fractional = value.f & (one.f - 1);
-  exp = count_digits(integral);  // kappa in Grisu.
+  exp = grisu_count_digits(integral);  // kappa in Grisu.
   // Divide by 10 to prevent overflow.
   auto result = handler.on_start(data::powers_of_10_64[exp - 1] << -one.e,
                                  value.f / 10, error * 10, exp);
@@ -882,8 +879,8 @@ struct fixed_handler {
     if (precision > 0) return digits::more;
     if (precision < 0) return digits::done;
     auto dir = get_round_direction(divisor, remainder, error);
-    if (dir == unknown) return digits::error;
-    buf[size++] = dir == up ? '1' : '0';
+    if (dir == round_direction::unknown) return digits::error;
+    buf[size++] = dir == round_direction::up ? '1' : '0';
     return digits::done;
   }
 
@@ -901,7 +898,8 @@ struct fixed_handler {
       FMT_ASSERT(error == 1 && divisor > 2, "");
     }
     auto dir = get_round_direction(divisor, remainder, error);
-    if (dir != up) return dir == down ? digits::done : digits::error;
+    if (dir != round_direction::up)
+      return dir == round_direction::down ? digits::done : digits::error;
     ++buf[size - 1];
     for (int i = size - 1; i > 0 && buf[i] > '9'; --i) {
       buf[i] = '0';
@@ -1028,7 +1026,7 @@ void fallback_format(Double d, buffer<char>& buf, int& exp10) {
         if (result > 0 || (result == 0 && (digit % 2) != 0))
           ++data[num_digits - 1];
       }
-      buf.resize(num_digits);
+      buf.resize(to_unsigned(num_digits));
       exp10 -= num_digits - 1;
       return;
     }
@@ -1043,7 +1041,7 @@ void fallback_format(Double d, buffer<char>& buf, int& exp10) {
 // if T is a IEEE754 binary32 or binary64 and snprintf otherwise.
 template <typename T>
 int format_float(T value, int precision, float_specs specs, buffer<char>& buf) {
-  static_assert(!std::is_same<T, float>(), "");
+  static_assert(!std::is_same<T, float>::value, "");
   FMT_ASSERT(value >= 0, "value is negative");
 
   const bool fixed = specs.format == float_format::fixed;
@@ -1062,25 +1060,7 @@ int format_float(T value, int precision, float_specs specs, buffer<char>& buf) {
   int exp = 0;
   const int min_exp = -60;  // alpha in Grisu.
   int cached_exp10 = 0;     // K in Grisu.
-  if (precision != -1) {
-    if (precision > 17) return snprintf_float(value, precision, specs, buf);
-    fp normalized = normalize(fp(value));
-    const auto cached_pow = get_cached_power(
-        min_exp - (normalized.e + fp::significand_size), cached_exp10);
-    normalized = normalized * cached_pow;
-    fixed_handler handler{buf.data(), 0, precision, -cached_exp10, fixed};
-    if (grisu_gen_digits(normalized, 1, exp, handler) == digits::error)
-      return snprintf_float(value, precision, specs, buf);
-    int num_digits = handler.size;
-    if (!fixed) {
-      // Remove trailing zeros.
-      while (num_digits > 0 && buf[num_digits - 1] == '0') {
-        --num_digits;
-        ++exp;
-      }
-    }
-    buf.resize(to_unsigned(num_digits));
-  } else {
+  if (precision < 0) {
     fp fp_value;
     auto boundaries = specs.binary32
                           ? fp_value.assign_float_with_boundaries(value)
@@ -1109,6 +1089,24 @@ int format_float(T value, int precision, float_specs specs, buffer<char>& buf) {
       return exp;
     }
     buf.resize(to_unsigned(handler.size));
+  } else {
+    if (precision > 17) return snprintf_float(value, precision, specs, buf);
+    fp normalized = normalize(fp(value));
+    const auto cached_pow = get_cached_power(
+        min_exp - (normalized.e + fp::significand_size), cached_exp10);
+    normalized = normalized * cached_pow;
+    fixed_handler handler{buf.data(), 0, precision, -cached_exp10, fixed};
+    if (grisu_gen_digits(normalized, 1, exp, handler) == digits::error)
+      return snprintf_float(value, precision, specs, buf);
+    int num_digits = handler.size;
+    if (!fixed) {
+      // Remove trailing zeros.
+      while (num_digits > 0 && buf[num_digits - 1] == '0') {
+        --num_digits;
+        ++exp;
+      }
+    }
+    buf.resize(to_unsigned(num_digits));
   }
   return exp - cached_exp10;
 }
@@ -1118,7 +1116,7 @@ int snprintf_float(T value, int precision, float_specs specs,
                    buffer<char>& buf) {
   // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
   FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer");
-  static_assert(!std::is_same<T, float>(), "");
+  static_assert(!std::is_same<T, float>::value, "");
 
   // Subtract 1 to account for the difference in precision since we use %e for
   // both general and exponent format.
@@ -1131,7 +1129,7 @@ int snprintf_float(T value, int precision, float_specs specs,
   char format[max_format_size];
   char* format_ptr = format;
   *format_ptr++ = '%';
-  if (specs.trailing_zeros) *format_ptr++ = '#';
+  if (specs.showpoint && specs.format == float_format::hex) *format_ptr++ = '#';
   if (precision >= 0) {
     *format_ptr++ = '.';
     *format_ptr++ = '*';
@@ -1153,7 +1151,8 @@ int snprintf_float(T value, int precision, float_specs specs,
           "fuzz mode - avoid large allocation inside snprintf");
 #endif
     // Suppress the warning about a nonliteral format string.
-    auto snprintf_ptr = FMT_SNPRINTF;
+    // Cannot use auto becase of a bug in MinGW (#1532).
+    int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF;
     int result = precision >= 0
                      ? snprintf_ptr(begin, capacity, format, precision, value)
                      : snprintf_ptr(begin, capacity, format, value);
@@ -1161,7 +1160,7 @@ int snprintf_float(T value, int precision, float_specs specs,
       buf.reserve(buf.capacity() + 1);  // The buffer will grow exponentially.
       continue;
     }
-    unsigned size = to_unsigned(result);
+    auto size = to_unsigned(result);
     // Size equal to capacity means that the last character was truncated.
     if (size >= capacity) {
       buf.reserve(size + offset + 1);  // Add 1 for the terminating '\0'.
@@ -1179,7 +1178,7 @@ int snprintf_float(T value, int precision, float_specs specs,
         --p;
       } while (is_digit(*p));
       int fraction_size = static_cast<int>(end - p - 1);
-      std::memmove(p, p + 1, fraction_size);
+      std::memmove(p, p + 1, to_unsigned(fraction_size));
       buf.resize(size - 1);
       return -fraction_size;
     }
@@ -1208,12 +1207,67 @@ int snprintf_float(T value, int precision, float_specs specs,
       while (*fraction_end == '0') --fraction_end;
       // Move the fractional part left to get rid of the decimal point.
       fraction_size = static_cast<int>(fraction_end - begin - 1);
-      std::memmove(begin + 1, begin + 2, fraction_size);
+      std::memmove(begin + 1, begin + 2, to_unsigned(fraction_size));
     }
-    buf.resize(fraction_size + offset + 1);
+    buf.resize(to_unsigned(fraction_size) + offset + 1);
     return exp - fraction_size;
   }
 }
+
+// A public domain branchless UTF-8 decoder by Christopher Wellons:
+// https://github.com/skeeto/branchless-utf8
+/* Decode the next character, c, from buf, reporting errors in e.
+ *
+ * Since this is a branchless decoder, four bytes will be read from the
+ * buffer regardless of the actual length of the next character. This
+ * means the buffer _must_ have at least three bytes of zero padding
+ * following the end of the data stream.
+ *
+ * Errors are reported in e, which will be non-zero if the parsed
+ * character was somehow invalid: invalid byte sequence, non-canonical
+ * encoding, or a surrogate half.
+ *
+ * The function returns a pointer to the next character. When an error
+ * occurs, this pointer will be a guess that depends on the particular
+ * error, but it will always advance at least one byte.
+ */
+FMT_FUNC const char* utf8_decode(const char* buf, uint32_t* c, int* e) {
+  static const char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                                 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+                                 0, 0, 2, 2, 2, 2, 3, 3, 4, 0};
+  static const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
+  static const uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
+  static const int shiftc[] = {0, 18, 12, 6, 0};
+  static const int shifte[] = {0, 6, 4, 2, 0};
+
+  auto s = reinterpret_cast<const unsigned char*>(buf);
+  int len = lengths[s[0] >> 3];
+
+  // Compute the pointer to the next character early so that the next
+  // iteration can start working on the next character. Neither Clang
+  // nor GCC figure out this reordering on their own.
+  const char* next = buf + len + !len;
+
+  // Assume a four-byte character and load four bytes. Unused bits are
+  // shifted out.
+  *c = uint32_t(s[0] & masks[len]) << 18;
+  *c |= uint32_t(s[1] & 0x3f) << 12;
+  *c |= uint32_t(s[2] & 0x3f) << 6;
+  *c |= uint32_t(s[3] & 0x3f) << 0;
+  *c >>= shiftc[len];
+
+  // Accumulate the various error conditions.
+  *e = (*c < mins[len]) << 6;       // non-canonical encoding
+  *e |= ((*c >> 11) == 0x1b) << 7;  // surrogate half?
+  *e |= (*c > 0x10FFFF) << 8;       // out of range?
+  *e |= (s[1] & 0xc0) >> 2;
+  *e |= (s[2] & 0xc0) >> 4;
+  *e |= (s[3]) >> 6;
+  *e ^= 0x2a;  // top two bits of each tail byte correct?
+  *e >>= shifte[len];
+
+  return next;
+}
 }  // namespace internal
 
 template <> struct formatter<internal::bigint> {
@@ -1226,7 +1280,7 @@ template <> struct formatter<internal::bigint> {
     auto out = ctx.out();
     bool first = true;
     for (auto i = n.bigits_.size(); i > 0; --i) {
-      auto value = n.bigits_[i - 1];
+      auto value = n.bigits_[i - 1u];
       if (first) {
         out = format_to(out, "{:x}", value);
         first = false;
@@ -1240,101 +1294,37 @@ template <> struct formatter<internal::bigint> {
   }
 };
 
-#if FMT_USE_WINDOWS_H
-
 FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
-  static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
-  if (s.size() > INT_MAX)
-    FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG));
-  int s_size = static_cast<int>(s.size());
-  if (s_size == 0) {
-    // MultiByteToWideChar does not support zero length, handle separately.
-    buffer_.resize(1);
-    buffer_[0] = 0;
-    return;
-  }
-
-  int length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(),
-                                   s_size, nullptr, 0);
-  if (length == 0) FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
-  buffer_.resize(length + 1);
-  length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size,
-                               &buffer_[0], length);
-  if (length == 0) FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
-  buffer_[length] = 0;
-}
-
-FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
-  if (int error_code = convert(s)) {
-    FMT_THROW(windows_error(error_code,
-                            "cannot convert string from UTF-16 to UTF-8"));
-  }
-}
-
-FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
-  if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER;
-  int s_size = static_cast<int>(s.size());
-  if (s_size == 0) {
-    // WideCharToMultiByte does not support zero length, handle separately.
-    buffer_.resize(1);
-    buffer_[0] = 0;
-    return 0;
-  }
-
-  int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, nullptr, 0,
-                                   nullptr, nullptr);
-  if (length == 0) return GetLastError();
-  buffer_.resize(length + 1);
-  length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0],
-                               length, nullptr, nullptr);
-  if (length == 0) return GetLastError();
-  buffer_[length] = 0;
-  return 0;
-}
-
-FMT_FUNC void windows_error::init(int err_code, string_view format_str,
-                                  format_args args) {
-  error_code_ = err_code;
-  memory_buffer buffer;
-  internal::format_windows_error(buffer, err_code, vformat(format_str, args));
-  std::runtime_error& base = *this;
-  base = std::runtime_error(to_string(buffer));
-}
-
-FMT_FUNC void internal::format_windows_error(internal::buffer<char>& out,
-                                             int error_code,
-                                             string_view message) FMT_NOEXCEPT {
-  FMT_TRY {
-    wmemory_buffer buf;
-    buf.resize(inline_buffer_size);
-    for (;;) {
-      wchar_t* system_message = &buf[0];
-      int result = FormatMessageW(
-          FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
-          error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message,
-          static_cast<uint32_t>(buf.size()), nullptr);
-      if (result != 0) {
-        utf16_to_utf8 utf8_message;
-        if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
-          internal::writer w(out);
-          w.write(message);
-          w.write(": ");
-          w.write(utf8_message);
-          return;
-        }
-        break;
-      }
-      if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
-        break;  // Can't get error message, report error code instead.
-      buf.resize(buf.size() * 2);
+  auto transcode = [this](const char* p) {
+    auto cp = uint32_t();
+    auto error = 0;
+    p = utf8_decode(p, &cp, &error);
+    if (error != 0) FMT_THROW(std::runtime_error("invalid utf8"));
+    if (cp <= 0xFFFF) {
+      buffer_.push_back(static_cast<wchar_t>(cp));
+    } else {
+      cp -= 0x10000;
+      buffer_.push_back(static_cast<wchar_t>(0xD800 + (cp >> 10)));
+      buffer_.push_back(static_cast<wchar_t>(0xDC00 + (cp & 0x3FF)));
     }
+    return p;
+  };
+  auto p = s.data();
+  const size_t block_size = 4;  // utf8_decode always reads blocks of 4 chars.
+  if (s.size() >= block_size) {
+    for (auto end = p + s.size() - block_size + 1; p < end;) p = transcode(p);
   }
-  FMT_CATCH(...) {}
-  format_error_code(out, error_code, message);
+  if (auto num_chars_left = s.data() + s.size() - p) {
+    char buf[2 * block_size - 1] = {};
+    memcpy(buf, p, to_unsigned(num_chars_left));
+    p = buf;
+    do {
+      p = transcode(p);
+    } while (p - buf < num_chars_left);
+  }
+  buffer_.push_back(0);
 }
 
-#endif  // FMT_USE_WINDOWS_H
-
 FMT_FUNC void format_system_error(internal::buffer<char>& out, int error_code,
                                   string_view message) FMT_NOEXCEPT {
   FMT_TRY {
@@ -1369,20 +1359,37 @@ FMT_FUNC void report_system_error(int error_code,
   report_error(format_system_error, error_code, message);
 }
 
-#if FMT_USE_WINDOWS_H
-FMT_FUNC void report_windows_error(int error_code,
-                                   fmt::string_view message) FMT_NOEXCEPT {
-  report_error(internal::format_windows_error, error_code, message);
-}
-#endif
-
 FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
   memory_buffer buffer;
   internal::vformat_to(buffer, format_str,
                        basic_format_args<buffer_context<char>>(args));
+#ifdef _WIN32
+  auto fd = _fileno(f);
+  if (_isatty(fd)) {
+    internal::utf8_to_utf16 u16(string_view(buffer.data(), buffer.size()));
+    auto written = DWORD();
+    if (!WriteConsoleW(reinterpret_cast<HANDLE>(_get_osfhandle(fd)),
+                       u16.c_str(), static_cast<DWORD>(u16.size()), &written,
+                       nullptr)) {
+      FMT_THROW(format_error("failed to write to console"));
+    }
+    return;
+  }
+#endif
   internal::fwrite_fully(buffer.data(), 1, buffer.size(), f);
 }
 
+#ifdef _WIN32
+// Print assuming legacy (non-Unicode) encoding.
+FMT_FUNC void internal::vprint_mojibake(std::FILE* f, string_view format_str,
+                                        format_args args) {
+  memory_buffer buffer;
+  internal::vformat_to(buffer, format_str,
+                       basic_format_args<buffer_context<char>>(args));
+  fwrite_fully(buffer.data(), 1, buffer.size(), f);
+}
+#endif
+
 FMT_FUNC void vprint(string_view format_str, format_args args) {
   vprint(stdout, format_str, args);
 }
index 01f41f5cbdd339c4106caa7056a00fef38b5f477..4e96539fa2a078c093d77e9d30a83752339fda24 100644 (file)
@@ -33,8 +33,6 @@
 #ifndef FMT_FORMAT_H_
 #define FMT_FORMAT_H_
 
-#include "core.h"
-
 #include <algorithm>
 #include <cerrno>
 #include <cmath>
 #include <memory>
 #include <stdexcept>
 
-#ifdef __clang__
-#  define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
-#else
-#  define FMT_CLANG_VERSION 0
+#include "core.h"
+
+#ifdef FMT_DEPRECATED_INCLUDE_OS
+#  include "os.h"
 #endif
 
 #ifdef __INTEL_COMPILER
 #  define FMT_HAS_BUILTIN(x) 0
 #endif
 
-#if FMT_HAS_CPP_ATTRIBUTE(fallthrough) && \
-    (__cplusplus >= 201703 || FMT_GCC_VERSION != 0)
+#if FMT_GCC_VERSION || FMT_CLANG_VERSION
+#  define FMT_NOINLINE __attribute__((noinline))
+#else
+#  define FMT_NOINLINE
+#endif
+
+#if __cplusplus == 201103L || __cplusplus == 201402L
+#  if defined(__clang__)
+#    define FMT_FALLTHROUGH [[clang::fallthrough]]
+#  elif FMT_GCC_VERSION >= 700 && !defined(__PGI)
+#    define FMT_FALLTHROUGH [[gnu::fallthrough]]
+#  else
+#    define FMT_FALLTHROUGH
+#  endif
+#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) || \
+    (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
 #  define FMT_FALLTHROUGH [[fallthrough]]
 #else
 #  define FMT_FALLTHROUGH
 
 #ifndef FMT_THROW
 #  if FMT_EXCEPTIONS
-#    if FMT_MSC_VER
+#    if FMT_MSC_VER || FMT_NVCC
 FMT_BEGIN_NAMESPACE
 namespace internal {
 template <typename Exception> inline void do_throw(const Exception& x) {
-  // Silence unreachable code warnings in MSVC because these are nearly
-  // impossible to fix in a generic code.
+  // Silence unreachable code warnings in MSVC and NVCC because these
+  // are nearly impossible to fix in a generic code.
   volatile bool b = true;
   if (b) throw x;
 }
@@ -102,6 +114,14 @@ FMT_END_NAMESPACE
 #  endif
 #endif
 
+#if FMT_EXCEPTIONS
+#  define FMT_TRY try
+#  define FMT_CATCH(x) catch (x)
+#else
+#  define FMT_TRY if (true)
+#  define FMT_CATCH(x) if (false)
+#endif
+
 #ifndef FMT_USE_USER_DEFINED_LITERALS
 // For Intel and NVIDIA compilers both they and the system gcc/msc support UDLs.
 #  if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 ||      \
@@ -115,11 +135,11 @@ FMT_END_NAMESPACE
 #endif
 
 #ifndef FMT_USE_UDL_TEMPLATE
-// EDG front end based compilers (icc, nvcc) do not support UDL templates yet
-// and GCC 9 warns about them.
+// EDG front end based compilers (icc, nvcc) and GCC < 6.4 do not propertly
+// support UDL templates and GCC >= 9 warns about them.
 #  if FMT_USE_USER_DEFINED_LITERALS && FMT_ICC_VERSION == 0 && \
       FMT_CUDA_VERSION == 0 &&                                 \
-      ((FMT_GCC_VERSION >= 600 && FMT_GCC_VERSION <= 900 &&    \
+      ((FMT_GCC_VERSION >= 604 && FMT_GCC_VERSION <= 900 &&    \
         __cplusplus >= 201402L) ||                             \
        FMT_CLANG_VERSION >= 304)
 #    define FMT_USE_UDL_TEMPLATE 1
@@ -128,6 +148,18 @@ FMT_END_NAMESPACE
 #  endif
 #endif
 
+#ifndef FMT_USE_FLOAT
+#  define FMT_USE_FLOAT 1
+#endif
+
+#ifndef FMT_USE_DOUBLE
+#  define FMT_USE_DOUBLE 1
+#endif
+
+#ifndef FMT_USE_LONG_DOUBLE
+#  define FMT_USE_LONG_DOUBLE 1
+#endif
+
 // __builtin_clz is broken in clang with Microsoft CodeGen:
 // https://github.com/fmtlib/fmt/issues/519
 #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)) && !FMT_MSC_VER
@@ -203,10 +235,6 @@ FMT_END_NAMESPACE
 FMT_BEGIN_NAMESPACE
 namespace internal {
 
-// A helper function to suppress bogus "conditional expression is constant"
-// warnings.
-template <typename T> inline T const_check(T value) { return value; }
-
 // An equivalent of `*reinterpret_cast<Dest*>(&source)` that doesn't have
 // undefined behavior (e.g. due to type aliasing).
 // Example: uint64_t d = bit_cast<uint64_t>(2.718);
@@ -219,7 +247,7 @@ inline Dest bit_cast(const Source& source) {
 }
 
 inline bool is_big_endian() {
-  auto u = 1u;
+  const auto u = 1u;
   struct bytes {
     char data[sizeof(u)];
   };
@@ -296,7 +324,7 @@ template <typename It> class is_output_iterator {
   using type = decltype(test<It>(typename iterator_category<It>::type{}));
 
  public:
-  static const bool value = !std::is_const<remove_reference_t<type>>::value;
+  enum { value = !std::is_const<remove_reference_t<type>>::value };
 };
 
 // A workaround for std::string not having mutable data() until C++17.
@@ -308,7 +336,7 @@ inline typename Container::value_type* get_data(Container& c) {
   return c.data();
 }
 
-#ifdef _SECURE_SCL
+#if defined(_SECURE_SCL) && _SECURE_SCL
 // Make a checked iterator to avoid MSVC warnings.
 template <typename T> using checked_ptr = stdext::checked_array_iterator<T*>;
 template <typename T> checked_ptr<T> make_checked(T* p, std::size_t size) {
@@ -379,6 +407,7 @@ template <typename OutputIt> class truncating_iterator_base {
 
  public:
   using iterator_category = std::output_iterator_tag;
+  using value_type = typename std::iterator_traits<OutputIt>::value_type;
   using difference_type = void;
   using pointer = void;
   using reference = void;
@@ -399,12 +428,10 @@ class truncating_iterator;
 template <typename OutputIt>
 class truncating_iterator<OutputIt, std::false_type>
     : public truncating_iterator_base<OutputIt> {
-  using traits = std::iterator_traits<OutputIt>;
-
-  mutable typename traits::value_type blackhole_;
+  mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
 
  public:
-  using value_type = typename traits::value_type;
+  using value_type = typename truncating_iterator_base<OutputIt>::value_type;
 
   truncating_iterator(OutputIt out, std::size_t limit)
       : truncating_iterator_base<OutputIt>(out, limit) {}
@@ -429,13 +456,11 @@ template <typename OutputIt>
 class truncating_iterator<OutputIt, std::true_type>
     : public truncating_iterator_base<OutputIt> {
  public:
-  using value_type = typename OutputIt::container_type::value_type;
-
   truncating_iterator(OutputIt out, std::size_t limit)
       : truncating_iterator_base<OutputIt>(out, limit) {}
 
-  truncating_iterator& operator=(value_type val) {
-    if (this->count_++ < this->limit_) this->out_ = val;
+  template <typename T> truncating_iterator& operator=(T val) {
+    if (this->count_++ < this->limit_) *this->out_++ = val;
     return *this;
   }
 
@@ -466,8 +491,8 @@ inline size_t count_code_points(basic_string_view<Char> s) {
 }
 
 // Counts the number of code points in a UTF-8 string.
-inline size_t count_code_points(basic_string_view<char8_t> s) {
-  const char8_t* data = s.data();
+inline size_t count_code_points(basic_string_view<char> s) {
+  const char* data = s.data();
   size_t num_code_points = 0;
   for (size_t i = 0, size = s.size(); i != size; ++i) {
     if ((data[i] & 0xc0) != 0x80) ++num_code_points;
@@ -475,6 +500,11 @@ inline size_t count_code_points(basic_string_view<char8_t> s) {
   return num_code_points;
 }
 
+inline size_t count_code_points(basic_string_view<char8_type> s) {
+  return count_code_points(basic_string_view<char>(
+      reinterpret_cast<const char*>(s.data()), s.size()));
+}
+
 template <typename Char>
 inline size_t code_point_index(basic_string_view<Char> s, size_t n) {
   size_t size = s.size();
@@ -482,8 +512,8 @@ inline size_t code_point_index(basic_string_view<Char> s, size_t n) {
 }
 
 // Calculates the index of the nth code point in a UTF-8 string.
-inline size_t code_point_index(basic_string_view<char8_t> s, size_t n) {
-  const char8_t* data = s.data();
+inline size_t code_point_index(basic_string_view<char8_type> s, size_t n) {
+  const char8_type* data = s.data();
   size_t num_code_points = 0;
   for (size_t i = 0, size = s.size(); i != size; ++i) {
     if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) {
@@ -493,13 +523,13 @@ inline size_t code_point_index(basic_string_view<char8_t> s, size_t n) {
   return s.size();
 }
 
-inline char8_t to_char8_t(char c) { return static_cast<char8_t>(c); }
+inline char8_type to_char8_t(char c) { return static_cast<char8_type>(c); }
 
 template <typename InputIt, typename OutChar>
 using needs_conversion = bool_constant<
     std::is_same<typename std::iterator_traits<InputIt>::value_type,
                  char>::value &&
-    std::is_same<OutChar, char8_t>::value>;
+    std::is_same<OutChar, char8_type>::value>;
 
 template <typename OutChar, typename InputIt, typename OutputIt,
           FMT_ENABLE_IF(!needs_conversion<InputIt, OutChar>::value)>
@@ -543,20 +573,22 @@ class buffer_range : public internal::output_range<
       : internal::output_range<iterator, T>(std::back_inserter(buf)) {}
 };
 
-// A UTF-8 string view.
-class u8string_view : public basic_string_view<char8_t> {
+class FMT_DEPRECATED u8string_view
+    : public basic_string_view<internal::char8_type> {
  public:
   u8string_view(const char* s)
-      : basic_string_view<char8_t>(reinterpret_cast<const char8_t*>(s)) {}
+      : basic_string_view<internal::char8_type>(
+            reinterpret_cast<const internal::char8_type*>(s)) {}
   u8string_view(const char* s, size_t count) FMT_NOEXCEPT
-      : basic_string_view<char8_t>(reinterpret_cast<const char8_t*>(s), count) {
-  }
+      : basic_string_view<internal::char8_type>(
+            reinterpret_cast<const internal::char8_type*>(s), count) {}
 };
 
 #if FMT_USE_USER_DEFINED_LITERALS
 inline namespace literals {
-inline u8string_view operator"" _u(const char* s, std::size_t n) {
-  return {s, n};
+FMT_DEPRECATED inline basic_string_view<internal::char8_type> operator"" _u(
+    const char* s, std::size_t n) {
+  return {reinterpret_cast<const internal::char8_type*>(s), n};
 }
 }  // namespace literals
 #endif
@@ -688,6 +720,7 @@ using memory_buffer = basic_memory_buffer<char>;
 using wmemory_buffer = basic_memory_buffer<wchar_t>;
 
 /** A formatting error such as invalid format string. */
+FMT_CLASS_API
 class FMT_API format_error : public std::runtime_error {
  public:
   explicit format_error(const char* message) : std::runtime_error(message) {}
@@ -713,6 +746,13 @@ FMT_CONSTEXPR bool is_negative(T) {
   return false;
 }
 
+template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
+FMT_CONSTEXPR bool is_supported_floating_point(T) {
+  return (std::is_same<T, float>::value && FMT_USE_FLOAT) ||
+         (std::is_same<T, double>::value && FMT_USE_DOUBLE) ||
+         (std::is_same<T, long double>::value && FMT_USE_LONG_DOUBLE);
+}
+
 // Smallest of uint32_t, uint64_t, uint128_t that is large enough to
 // represent all values of T.
 template <typename T>
@@ -865,11 +905,11 @@ inline Char* format_decimal(Char* buffer, UInt value, int num_digits,
   return end;
 }
 
-template <typename Int> constexpr int digits10() noexcept {
+template <typename Int> constexpr int digits10() FMT_NOEXCEPT {
   return std::numeric_limits<Int>::digits10;
 }
-template <> constexpr int digits10<int128_t>() noexcept { return 38; }
-template <> constexpr int digits10<uint128_t>() noexcept { return 38; }
+template <> constexpr int digits10<int128_t>() FMT_NOEXCEPT { return 38; }
+template <> constexpr int digits10<uint128_t>() FMT_NOEXCEPT { return 38; }
 
 template <typename Char, typename UInt, typename Iterator, typename F>
 inline Iterator format_decimal(Iterator out, UInt value, int num_digits,
@@ -931,61 +971,42 @@ inline It format_uint(It out, UInt value, int num_digits, bool upper = false) {
   return internal::copy_str<Char>(buffer, buffer + num_digits, out);
 }
 
-#ifndef _WIN32
-#  define FMT_USE_WINDOWS_H 0
-#elif !defined(FMT_USE_WINDOWS_H)
-#  define FMT_USE_WINDOWS_H 1
-#endif
-
-// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h.
-// All the functionality that relies on it will be disabled too.
-#if FMT_USE_WINDOWS_H
 // A converter from UTF-8 to UTF-16.
-// It is only provided for Windows since other systems support UTF-8 natively.
 class utf8_to_utf16 {
  private:
   wmemory_buffer buffer_;
 
  public:
   FMT_API explicit utf8_to_utf16(string_view s);
-  operator wstring_view() const { return wstring_view(&buffer_[0], size()); }
+  operator wstring_view() const { return {&buffer_[0], size()}; }
   size_t size() const { return buffer_.size() - 1; }
   const wchar_t* c_str() const { return &buffer_[0]; }
-  std::wstring str() const { return std::wstring(&buffer_[0], size()); }
+  std::wstring str() const { return {&buffer_[0], size()}; }
 };
 
-// A converter from UTF-16 to UTF-8.
-// It is only provided for Windows since other systems support UTF-8 natively.
-class utf16_to_utf8 {
- private:
-  memory_buffer buffer_;
-
- public:
-  utf16_to_utf8() {}
-  FMT_API explicit utf16_to_utf8(wstring_view s);
-  operator string_view() const { return string_view(&buffer_[0], size()); }
-  size_t size() const { return buffer_.size() - 1; }
-  const char* c_str() const { return &buffer_[0]; }
-  std::string str() const { return std::string(&buffer_[0], size()); }
-
-  // Performs conversion returning a system error code instead of
-  // throwing exception on conversion error. This method may still throw
-  // in case of memory allocation error.
-  FMT_API int convert(wstring_view s);
-};
-
-FMT_API void format_windows_error(internal::buffer<char>& out, int error_code,
-                                  string_view message) FMT_NOEXCEPT;
-#endif
-
 template <typename T = void> struct null {};
 
 // Workaround an array initialization issue in gcc 4.8.
 template <typename Char> struct fill_t {
  private:
-  Char data_[6];
+  enum { max_size = 4 };
+  Char data_[max_size];
+  unsigned char size_;
 
  public:
+  FMT_CONSTEXPR void operator=(basic_string_view<Char> s) {
+    auto size = s.size();
+    if (size > max_size) {
+      FMT_THROW(format_error("invalid fill"));
+      return;
+    }
+    for (size_t i = 0; i < size; ++i) data_[i] = s[i];
+    size_ = static_cast<unsigned char>(size);
+  }
+
+  size_t size() const { return size_; }
+  const Char* data() const { return data_; }
+
   FMT_CONSTEXPR Char& operator[](size_t index) { return data_[index]; }
   FMT_CONSTEXPR const Char& operator[](size_t index) const {
     return data_[index];
@@ -994,6 +1015,7 @@ template <typename Char> struct fill_t {
   static FMT_CONSTEXPR fill_t<Char> make() {
     auto fill = fill_t<Char>();
     fill[0] = Char(' ');
+    fill.size_ = 1;
     return fill;
   }
 };
@@ -1052,7 +1074,7 @@ struct float_specs {
   bool percent : 1;
   bool binary32 : 1;
   bool use_grisu : 1;
-  bool trailing_zeros : 1;
+  bool showpoint : 1;
 };
 
 // Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
@@ -1093,10 +1115,9 @@ template <typename Char> class float_writer {
       // Insert a decimal point after the first digit and add an exponent.
       *it++ = static_cast<Char>(*digits_);
       int num_zeros = specs_.precision - num_digits_;
-      bool trailing_zeros = num_zeros > 0 && specs_.trailing_zeros;
-      if (num_digits_ > 1 || trailing_zeros) *it++ = decimal_point_;
+      if (num_digits_ > 1 || specs_.showpoint) *it++ = decimal_point_;
       it = copy_str<Char>(digits_ + 1, digits_ + num_digits_, it);
-      if (trailing_zeros)
+      if (num_zeros > 0 && specs_.showpoint)
         it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
       *it++ = static_cast<Char>(specs_.upper ? 'E' : 'e');
       return write_exponent<Char>(full_exp - 1, it);
@@ -1105,7 +1126,7 @@ template <typename Char> class float_writer {
       // 1234e7 -> 12340000000[.0+]
       it = copy_str<Char>(digits_, digits_ + num_digits_, it);
       it = std::fill_n(it, full_exp - num_digits_, static_cast<Char>('0'));
-      if (specs_.trailing_zeros) {
+      if (specs_.showpoint || specs_.precision < 0) {
         *it++ = decimal_point_;
         int num_zeros = specs_.precision - full_exp;
         if (num_zeros <= 0) {
@@ -1122,7 +1143,7 @@ template <typename Char> class float_writer {
     } else if (full_exp > 0) {
       // 1234e-2 -> 12.34[0+]
       it = copy_str<Char>(digits_, digits_ + full_exp, it);
-      if (!specs_.trailing_zeros) {
+      if (!specs_.showpoint) {
         // Remove trailing zeros.
         int num_digits = num_digits_;
         while (num_digits > full_exp && digits_[num_digits - 1] == '0')
@@ -1141,12 +1162,15 @@ template <typename Char> class float_writer {
       // 1234e-6 -> 0.001234
       *it++ = static_cast<Char>('0');
       int num_zeros = -full_exp;
-      if (specs_.precision >= 0 && specs_.precision < num_zeros)
-        num_zeros = specs_.precision;
       int num_digits = num_digits_;
-      if (!specs_.trailing_zeros)
+      if (num_digits == 0 && specs_.precision >= 0 &&
+          specs_.precision < num_zeros) {
+        num_zeros = specs_.precision;
+      }
+      // Remove trailing zeros.
+      if (!specs_.showpoint)
         while (num_digits > 0 && digits_[num_digits - 1] == '0') --num_digits;
-      if (num_zeros != 0 || num_digits != 0) {
+      if (num_zeros != 0 || num_digits != 0 || specs_.showpoint) {
         *it++ = decimal_point_;
         it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
         it = copy_str<Char>(digits_, digits_ + num_digits, it);
@@ -1191,7 +1215,7 @@ int snprintf_float(T value, int precision, float_specs specs,
                    buffer<char>& buf);
 
 template <typename T> T promote_float(T value) { return value; }
-inline double promote_float(float value) { return value; }
+inline double promote_float(float value) { return static_cast<double>(value); }
 
 template <typename Handler>
 FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) {
@@ -1212,6 +1236,7 @@ FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) {
     handler.on_oct();
     break;
   case 'n':
+  case 'L':
     handler.on_num();
     break;
   default:
@@ -1223,11 +1248,11 @@ template <typename ErrorHandler = error_handler, typename Char>
 FMT_CONSTEXPR float_specs parse_float_type_spec(
     const basic_format_specs<Char>& specs, ErrorHandler&& eh = {}) {
   auto result = float_specs();
-  result.trailing_zeros = specs.alt;
+  result.showpoint = specs.alt;
   switch (specs.type) {
   case 0:
     result.format = float_format::general;
-    result.trailing_zeros |= specs.precision != 0;
+    result.showpoint |= specs.precision > 0;
     break;
   case 'G':
     result.upper = true;
@@ -1240,14 +1265,14 @@ FMT_CONSTEXPR float_specs parse_float_type_spec(
     FMT_FALLTHROUGH;
   case 'e':
     result.format = float_format::exp;
-    result.trailing_zeros |= specs.precision != 0;
+    result.showpoint |= specs.precision != 0;
     break;
   case 'F':
     result.upper = true;
     FMT_FALLTHROUGH;
   case 'f':
     result.format = float_format::fixed;
-    result.trailing_zeros |= specs.precision != 0;
+    result.showpoint |= specs.precision != 0;
     break;
 #if FMT_DEPRECATED_PERCENT
   case '%':
@@ -1348,13 +1373,14 @@ void arg_map<Context>::init(const basic_format_args<Context>& args) {
   if (args.is_packed()) {
     for (int i = 0;; ++i) {
       internal::type arg_type = args.type(i);
-      if (arg_type == internal::none_type) return;
-      if (arg_type == internal::named_arg_type) push_back(args.values_[i]);
+      if (arg_type == internal::type::none_type) return;
+      if (arg_type == internal::type::named_arg_type)
+        push_back(args.values_[i]);
     }
   }
   for (int i = 0, n = args.max_size(); i < n; ++i) {
     auto type = args.args_[i].type_;
-    if (type == internal::named_arg_type) push_back(args.args_[i].value_);
+    if (type == internal::type::named_arg_type) push_back(args.args_[i].value_);
   }
 }
 
@@ -1372,6 +1398,14 @@ template <typename Char> struct nonfinite_writer {
   }
 };
 
+template <typename OutputIt, typename Char>
+FMT_NOINLINE OutputIt fill(OutputIt it, size_t n, const fill_t<Char>& fill) {
+  auto fill_size = fill.size();
+  if (fill_size == 1) return std::fill_n(it, n, fill[0]);
+  for (size_t i = 0; i < n; ++i) it = std::copy_n(fill.data(), fill_size, it);
+  return it;
+}
+
 // This template provides operations for formatting and writing data into a
 // character range.
 template <typename Range> class basic_writer {
@@ -1605,6 +1639,18 @@ template <typename Range> class basic_writer {
     }
   };
 
+  struct bytes_writer {
+    string_view bytes;
+
+    size_t size() const { return bytes.size(); }
+    size_t width() const { return bytes.size(); }
+
+    template <typename It> void operator()(It&& it) const {
+      const char* data = bytes.data();
+      it = copy_str<char>(data, data + size(), it);
+    }
+  };
+
   template <typename UIntPtr> struct pointer_writer {
     UIntPtr value;
     int num_digits;
@@ -1634,20 +1680,20 @@ template <typename Range> class basic_writer {
     size_t size = f.size();  // The number of code units.
     size_t num_code_points = width != 0 ? f.width() : size;
     if (width <= num_code_points) return f(reserve(size));
-    auto&& it = reserve(width + (size - num_code_points));
-    char_type fill = specs.fill[0];
-    std::size_t padding = width - num_code_points;
+    size_t padding = width - num_code_points;
+    size_t fill_size = specs.fill.size();
+    auto&& it = reserve(size + padding * fill_size);
     if (specs.align == align::right) {
-      it = std::fill_n(it, padding, fill);
+      it = fill(it, padding, specs.fill);
       f(it);
     } else if (specs.align == align::center) {
       std::size_t left_padding = padding / 2;
-      it = std::fill_n(it, left_padding, fill);
+      it = fill(it, left_padding, specs.fill);
       f(it);
-      it = std::fill_n(it, padding - left_padding, fill);
+      it = fill(it, padding - left_padding, specs.fill);
     } else {
       f(it);
-      it = std::fill_n(it, padding, fill);
+      it = fill(it, padding, specs.fill);
     }
   }
 
@@ -1671,6 +1717,9 @@ template <typename Range> class basic_writer {
 
   template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
   void write(T value, format_specs specs = {}) {
+    if (const_check(!is_supported_floating_point(value))) {
+      return;
+    }
     float_specs fspecs = parse_float_type_spec(specs);
     fspecs.sign = specs.sign;
     if (std::signbit(value)) {  // value < 0 is false for NaN so use signbit.
@@ -1706,7 +1755,12 @@ template <typename Range> class basic_writer {
       return;
     }
     int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6;
-    if (fspecs.format == float_format::exp) ++precision;
+    if (fspecs.format == float_format::exp) {
+      if (precision == max_value<int>())
+        FMT_THROW(format_error("number is too big"));
+      else
+        ++precision;
+    }
     if (const_check(std::is_same<T, float>())) fspecs.binary32 = true;
     fspecs.use_grisu = use_grisu<T>();
     if (const_check(FMT_DEPRECATED_PERCENT) && fspecs.percent) value *= 100;
@@ -1758,6 +1812,10 @@ template <typename Range> class basic_writer {
     write(data, size, specs);
   }
 
+  void write_bytes(string_view bytes, const format_specs& specs) {
+    write_padded(specs, bytes_writer{bytes});
+  }
+
   template <typename UIntPtr>
   void write_pointer(UIntPtr value, const format_specs* specs) {
     int num_digits = count_digits<4>(value);
@@ -1860,7 +1918,10 @@ class arg_formatter_base {
 
   template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
   iterator operator()(T value) {
-    writer_.write(value, specs_ ? *specs_ : format_specs());
+    if (const_check(is_supported_floating_point(value)))
+      writer_.write(value, specs_ ? *specs_ : format_specs());
+    else
+      FMT_ASSERT(false, "unsupported float argument type");
     return out();
   }
 
@@ -1926,10 +1987,6 @@ template <typename Char, typename ErrorHandler>
 FMT_CONSTEXPR int parse_nonnegative_int(const Char*& begin, const Char* end,
                                         ErrorHandler&& eh) {
   FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', "");
-  if (*begin == '0') {
-    ++begin;
-    return 0;
-  }
   unsigned value = 0;
   // Convert to unsigned to prevent a warning.
   constexpr unsigned max_int = max_value<int>();
@@ -2023,7 +2080,9 @@ template <typename Char> class specs_setter {
       : specs_(other.specs_) {}
 
   FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; }
-  FMT_CONSTEXPR void on_fill(Char fill) { specs_.fill[0] = fill; }
+  FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) {
+    specs_.fill = fill;
+  }
   FMT_CONSTEXPR void on_plus() { specs_.sign = sign::plus; }
   FMT_CONSTEXPR void on_minus() { specs_.sign = sign::minus; }
   FMT_CONSTEXPR void on_space() { specs_.sign = sign::space; }
@@ -2060,14 +2119,14 @@ template <typename ErrorHandler> class numeric_specs_checker {
 
   FMT_CONSTEXPR void check_sign() {
     require_numeric_argument();
-    if (is_integral_type(arg_type_) && arg_type_ != int_type &&
-        arg_type_ != long_long_type && arg_type_ != internal::char_type) {
+    if (is_integral_type(arg_type_) && arg_type_ != type::int_type &&
+        arg_type_ != type::long_long_type && arg_type_ != type::char_type) {
       error_handler_.on_error("format specifier requires signed argument");
     }
   }
 
   FMT_CONSTEXPR void check_precision() {
-    if (is_integral_type(arg_type_) || arg_type_ == internal::pointer_type)
+    if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type)
       error_handler_.on_error("precision not allowed for this argument type");
   }
 
@@ -2190,6 +2249,7 @@ enum class arg_id_kind { none, index, name };
 // An argument reference.
 template <typename Char> struct arg_ref {
   FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {}
+
   FMT_CONSTEXPR explicit arg_ref(int index)
       : kind(arg_id_kind::index), val(index) {}
   FMT_CONSTEXPR explicit arg_ref(basic_string_view<Char> name)
@@ -2282,7 +2342,11 @@ FMT_CONSTEXPR const Char* parse_arg_id(const Char* begin, const Char* end,
     return begin;
   }
   if (c >= '0' && c <= '9') {
-    int index = parse_nonnegative_int(begin, end, handler);
+    int index = 0;
+    if (c != '0')
+      index = parse_nonnegative_int(begin, end, handler);
+    else
+      ++begin;
     if (begin == end || (*begin != '}' && *begin != ':'))
       handler.on_error("invalid format string");
     else
@@ -2335,16 +2399,25 @@ template <typename SpecHandler, typename Char> struct precision_adapter {
   SpecHandler& handler;
 };
 
+template <typename Char>
+FMT_CONSTEXPR const Char* next_code_point(const Char* begin, const Char* end) {
+  if (const_check(sizeof(Char) != 1) || (*begin & 0x80) == 0) return begin + 1;
+  do {
+    ++begin;
+  } while (begin != end && (*begin & 0xc0) == 0x80);
+  return begin;
+}
+
 // Parses fill and alignment.
 template <typename Char, typename Handler>
 FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end,
                                       Handler&& handler) {
   FMT_ASSERT(begin != end, "");
   auto align = align::none;
-  int i = 0;
-  if (begin + 1 != end) ++i;
-  do {
-    switch (static_cast<char>(begin[i])) {
+  auto p = next_code_point(begin, end);
+  if (p == end) p = begin;
+  for (;;) {
+    switch (static_cast<char>(*p)) {
     case '<':
       align = align::left;
       break;
@@ -2361,18 +2434,21 @@ FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end,
       break;
     }
     if (align != align::none) {
-      if (i > 0) {
+      if (p != begin) {
         auto c = *begin;
         if (c == '{')
           return handler.on_error("invalid fill character '{'"), begin;
-        begin += 2;
-        handler.on_fill(c);
+        handler.on_fill(basic_string_view<Char>(begin, to_unsigned(p - begin)));
+        begin = p + 1;
       } else
         ++begin;
       handler.on_align(align);
       break;
+    } else if (p == begin) {
+      break;
     }
-  } while (i-- > 0);
+    p = begin;
+  }
   return begin;
 }
 
@@ -2520,7 +2596,7 @@ FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> format_str,
     // Doing two passes with memchr (one for '{' and another for '}') is up to
     // 2.5x faster than the naive one-pass implementation on big format strings.
     const Char* p = begin;
-    if (*begin != '{' && !find<IS_CONSTEXPR>(begin, end, '{', p))
+    if (*begin != '{' && !find<IS_CONSTEXPR>(begin + 1, end, '{', p))
       return write(begin, end);
     write(begin, p);
     ++p;
@@ -2554,7 +2630,7 @@ FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs(
   using context = buffer_context<char_type>;
   using mapped_type =
       conditional_t<internal::mapped_type_constant<T, context>::value !=
-                        internal::custom_type,
+                        type::custom_type,
                     decltype(arg_mapper<context>().map(std::declval<T>())), T>;
   auto f = conditional_t<has_formatter<mapped_type, context>::value,
                          formatter<mapped_type, char_type>,
@@ -2624,10 +2700,9 @@ FMT_CONSTEXPR bool do_check_format_string(basic_string_view<Char> s,
 template <typename... Args, typename S,
           enable_if_t<(is_compile_string<S>::value), int>>
 void check_format_string(S format_str) {
-  FMT_CONSTEXPR_DECL bool invalid_format =
-      internal::do_check_format_string<typename S::char_type,
-                                       internal::error_handler, Args...>(
-          to_string_view(format_str));
+  FMT_CONSTEXPR_DECL bool invalid_format = internal::do_check_format_string<
+      typename S::char_type, internal::error_handler,
+      remove_const_t<remove_reference_t<Args>>...>(to_string_view(format_str));
   (void)invalid_format;
 }
 
@@ -2647,6 +2722,14 @@ void handle_dynamic_spec(int& value, arg_ref<typename Context::char_type> ref,
     break;
   }
 }
+
+using format_func = void (*)(internal::buffer<char>&, int, string_view);
+
+FMT_API void format_error_code(buffer<char>& out, int error_code,
+                               string_view message) FMT_NOEXCEPT;
+
+FMT_API void report_error(format_func func, int error_code,
+                          string_view message) FMT_NOEXCEPT;
 }  // namespace internal
 
 template <typename Range>
@@ -2699,6 +2782,7 @@ class arg_formatter : public internal::arg_formatter_base<Range> {
  An error returned by an operating system or a language runtime,
  for example a file opening error.
 */
+FMT_CLASS_API
 class FMT_API system_error : public std::runtime_error {
  private:
   void init(int err_code, string_view format_str, format_args args);
@@ -2765,55 +2849,6 @@ FMT_API void format_system_error(internal::buffer<char>& out, int error_code,
 FMT_API void report_system_error(int error_code,
                                  string_view message) FMT_NOEXCEPT;
 
-#if FMT_USE_WINDOWS_H
-
-/** A Windows error. */
-class windows_error : public system_error {
- private:
-  FMT_API void init(int error_code, string_view format_str, format_args args);
-
- public:
-  /**
-   \rst
-   Constructs a :class:`fmt::windows_error` object with the description
-   of the form
-
-   .. parsed-literal::
-     *<message>*: *<system-message>*
-
-   where *<message>* is the formatted message and *<system-message>* is the
-   system message corresponding to the error code.
-   *error_code* is a Windows error code as given by ``GetLastError``.
-   If *error_code* is not a valid error code such as -1, the system message
-   will look like "error -1".
-
-   **Example**::
-
-     // This throws a windows_error with the description
-     //   cannot open file 'madeup': The system cannot find the file specified.
-     // or similar (system message may vary).
-     const char *filename = "madeup";
-     LPOFSTRUCT of = LPOFSTRUCT();
-     HFILE file = OpenFile(filename, &of, OF_READ);
-     if (file == HFILE_ERROR) {
-       throw fmt::windows_error(GetLastError(),
-                                "cannot open file '{}'", filename);
-     }
-   \endrst
-  */
-  template <typename... Args>
-  windows_error(int error_code, string_view message, const Args&... args) {
-    init(error_code, message, make_format_args(args...));
-  }
-};
-
-// Reports a Windows error without throwing an exception.
-// Can be used to report errors from destructors.
-FMT_API void report_windows_error(int error_code,
-                                  string_view message) FMT_NOEXCEPT;
-
-#endif
-
 /** Fast integer formatter. */
 class format_int {
  private:
@@ -2894,7 +2929,7 @@ class format_int {
 template <typename T, typename Char>
 struct formatter<T, Char,
                  enable_if_t<internal::type_constant<T, Char>::value !=
-                             internal::custom_type>> {
+                             internal::type::custom_type>> {
   FMT_CONSTEXPR formatter() = default;
 
   // Parses format specifiers stopping either at the end of the range or at the
@@ -2908,40 +2943,56 @@ struct formatter<T, Char,
     auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
     auto eh = ctx.error_handler();
     switch (type) {
-    case internal::none_type:
-    case internal::named_arg_type:
+    case internal::type::none_type:
+    case internal::type::named_arg_type:
       FMT_ASSERT(false, "invalid argument type");
       break;
-    case internal::int_type:
-    case internal::uint_type:
-    case internal::long_long_type:
-    case internal::ulong_long_type:
-    case internal::int128_type:
-    case internal::uint128_type:
-    case internal::bool_type:
+    case internal::type::int_type:
+    case internal::type::uint_type:
+    case internal::type::long_long_type:
+    case internal::type::ulong_long_type:
+    case internal::type::int128_type:
+    case internal::type::uint128_type:
+    case internal::type::bool_type:
       handle_int_type_spec(specs_.type,
                            internal::int_type_checker<decltype(eh)>(eh));
       break;
-    case internal::char_type:
+    case internal::type::char_type:
       handle_char_specs(
           &specs_, internal::char_specs_checker<decltype(eh)>(specs_.type, eh));
       break;
-    case internal::float_type:
-    case internal::double_type:
-    case internal::long_double_type:
-      internal::parse_float_type_spec(specs_, eh);
+    case internal::type::float_type:
+      if (internal::const_check(FMT_USE_FLOAT)) {
+        internal::parse_float_type_spec(specs_, eh);
+      } else {
+        FMT_ASSERT(false, "float support disabled");
+      }
+      break;
+    case internal::type::double_type:
+      if (internal::const_check(FMT_USE_DOUBLE)) {
+        internal::parse_float_type_spec(specs_, eh);
+      } else {
+        FMT_ASSERT(false, "double support disabled");
+      }
+      break;
+    case internal::type::long_double_type:
+      if (internal::const_check(FMT_USE_LONG_DOUBLE)) {
+        internal::parse_float_type_spec(specs_, eh);
+      } else {
+        FMT_ASSERT(false, "long double support disabled");
+      }
       break;
-    case internal::cstring_type:
+    case internal::type::cstring_type:
       internal::handle_cstring_type_spec(
           specs_.type, internal::cstring_type_checker<decltype(eh)>(eh));
       break;
-    case internal::string_type:
+    case internal::type::string_type:
       internal::check_string_type_spec(specs_.type, eh);
       break;
-    case internal::pointer_type:
+    case internal::type::pointer_type:
       internal::check_pointer_type_spec(specs_.type, eh);
       break;
-    case internal::custom_type:
+    case internal::type::custom_type:
       // Custom format specifiers should be checked in parse functions of
       // formatter specializations.
       break;
@@ -2970,7 +3021,7 @@ struct formatter<T, Char,
   template <typename Char>                                                    \
   struct formatter<Type, Char> : formatter<Base, Char> {                      \
     template <typename FormatContext>                                         \
-    auto format(const Type& val, FormatContext& ctx) -> decltype(ctx.out()) { \
+    auto format(Type const& val, FormatContext& ctx) -> decltype(ctx.out()) { \
       return formatter<Base, Char>::format(val, ctx);                         \
     }                                                                         \
   }
@@ -3077,7 +3128,8 @@ typename basic_format_context<Range, Char>::format_arg
 basic_format_context<Range, Char>::arg(basic_string_view<char_type> name) {
   map_.init(args_);
   format_arg arg = map_.find(name);
-  if (arg.type() == internal::none_type) this->on_error("argument not found");
+  if (arg.type() == internal::type::none_type)
+    this->on_error("argument not found");
   return arg;
 }
 
@@ -3164,6 +3216,43 @@ template <typename T> inline const void* ptr(const std::shared_ptr<T>& p) {
   return p.get();
 }
 
+class bytes {
+ private:
+  string_view data_;
+  friend struct formatter<bytes>;
+
+ public:
+  explicit bytes(string_view data) : data_(data) {}
+};
+
+template <> struct formatter<bytes> {
+  template <typename ParseContext>
+  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+    using handler_type = internal::dynamic_specs_handler<ParseContext>;
+    internal::specs_checker<handler_type> handler(handler_type(specs_, ctx),
+                                                  internal::type::string_type);
+    auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
+    internal::check_string_type_spec(specs_.type, ctx.error_handler());
+    return it;
+  }
+
+  template <typename FormatContext>
+  auto format(bytes b, FormatContext& ctx) -> decltype(ctx.out()) {
+    internal::handle_dynamic_spec<internal::width_checker>(
+        specs_.width, specs_.width_ref, ctx);
+    internal::handle_dynamic_spec<internal::precision_checker>(
+        specs_.precision, specs_.precision_ref, ctx);
+    using range_type =
+        internal::output_range<typename FormatContext::iterator, char>;
+    internal::basic_writer<range_type> writer(range_type(ctx.out()));
+    writer.write_bytes(b.data_, specs_);
+    return writer.out();
+  }
+
+ private:
+  internal::dynamic_format_specs<char> specs_;
+};
+
 template <typename It, typename Char> struct arg_join : internal::view {
   It begin;
   It end;
@@ -3216,6 +3305,11 @@ arg_join<It, wchar_t> join(It begin, It end, wstring_view sep) {
     std::vector<int> v = {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"
   \endrst
  */
 template <typename Range>
@@ -3233,7 +3327,6 @@ arg_join<internal::iterator_t<const Range>, wchar_t> join(const Range& range,
 /**
   \rst
   Converts *value* to ``std::string`` using the default format for type *T*.
-  It doesn't support user-defined types with custom formatters.
 
   **Example**::
 
@@ -3261,7 +3354,7 @@ std::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE>& buf) {
 template <typename Char>
 typename buffer_context<Char>::iterator internal::vformat_to(
     internal::buffer<Char>& buf, basic_string_view<Char> format_str,
-    basic_format_args<buffer_context<Char>> args) {
+    basic_format_args<buffer_context<type_identity_t<Char>>> args) {
   using range = buffer_range<Char>;
   return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str),
                                           args);
@@ -3271,7 +3364,7 @@ template <typename S, typename Char = char_t<S>,
           FMT_ENABLE_IF(internal::is_string<S>::value)>
 inline typename buffer_context<Char>::iterator vformat_to(
     internal::buffer<Char>& buf, const S& format_str,
-    basic_format_args<buffer_context<Char>> args) {
+    basic_format_args<buffer_context<type_identity_t<Char>>> args) {
   return internal::vformat_to(buf, to_string_view(format_str), args);
 }
 
@@ -3282,7 +3375,7 @@ inline typename buffer_context<Char>::iterator format_to(
   internal::check_format_string<Args...>(format_str);
   using context = buffer_context<Char>;
   return internal::vformat_to(buf, to_string_view(format_str),
-                              {make_format_args<context>(args...)});
+                              make_format_args<context>(args...));
 }
 
 template <typename OutputIt, typename Char = char>
@@ -3295,8 +3388,9 @@ template <typename S, typename OutputIt, typename... Args,
           FMT_ENABLE_IF(
               internal::is_output_iterator<OutputIt>::value &&
               !internal::is_contiguous_back_insert_iterator<OutputIt>::value)>
-inline OutputIt vformat_to(OutputIt out, const S& format_str,
-                           format_args_t<OutputIt, char_t<S>> args) {
+inline OutputIt vformat_to(
+    OutputIt out, const S& format_str,
+    format_args_t<type_identity_t<OutputIt>, char_t<S>> args) {
   using range = internal::output_range<OutputIt, char_t<S>>;
   return vformat_to<arg_formatter<range>>(range(out),
                                           to_string_view(format_str), args);
@@ -3322,7 +3416,7 @@ inline OutputIt format_to(OutputIt out, const S& format_str, Args&&... args) {
   internal::check_format_string<Args...>(format_str);
   using context = format_context_t<OutputIt, char_t<S>>;
   return vformat_to(out, to_string_view(format_str),
-                    {make_format_args<context>(args...)});
+                    make_format_args<context>(args...));
 }
 
 template <typename OutputIt> struct format_to_n_result {
@@ -3350,7 +3444,7 @@ template <typename OutputIt, typename Char, typename... Args,
           FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)>
 inline format_to_n_result<OutputIt> vformat_to_n(
     OutputIt out, std::size_t n, basic_string_view<Char> format_str,
-    format_to_n_args<OutputIt, Char> args) {
+    format_to_n_args<type_identity_t<OutputIt>, type_identity_t<Char>> args) {
   auto it = vformat_to(internal::truncating_iterator<OutputIt>(out, n),
                        format_str, args);
   return {it.base(), it.count()};
@@ -3372,13 +3466,13 @@ inline format_to_n_result<OutputIt> format_to_n(OutputIt out, std::size_t n,
   internal::check_format_string<Args...>(format_str);
   using context = format_to_n_context<OutputIt, char_t<S>>;
   return vformat_to_n(out, n, to_string_view(format_str),
-                      {make_format_args<context>(args...)});
+                      make_format_args<context>(args...));
 }
 
 template <typename Char>
 inline std::basic_string<Char> internal::vformat(
     basic_string_view<Char> format_str,
-    basic_format_args<buffer_context<Char>> args) {
+    basic_format_args<buffer_context<type_identity_t<Char>>> args) {
   basic_memory_buffer<Char> buffer;
   internal::vformat_to(buffer, format_str, args);
   return to_string(buffer);
@@ -3443,6 +3537,22 @@ template <typename Char> struct udl_arg {
   }
 };
 
+// Converts string literals to basic_string_view.
+template <typename Char, size_t N>
+FMT_CONSTEXPR basic_string_view<Char> compile_string_to_view(
+    const Char (&s)[N]) {
+  // Remove trailing null character if needed. Won't be present if this is used
+  // with raw character array (i.e. not defined as a string).
+  return {s,
+          N - ((std::char_traits<Char>::to_int_type(s[N - 1]) == 0) ? 1 : 0)};
+}
+
+// Converts string_view to basic_string_view.
+template <typename Char>
+FMT_CONSTEXPR basic_string_view<Char> compile_string_to_view(
+    const std_string_view<Char>& s) {
+  return {s.data(), s.size()};
+}
 }  // namespace internal
 
 inline namespace literals {
@@ -3499,25 +3609,22 @@ FMT_CONSTEXPR internal::udl_arg<wchar_t> operator"" _a(const wchar_t* s,
 #endif  // FMT_USE_USER_DEFINED_LITERALS
 FMT_END_NAMESPACE
 
-#define FMT_STRING_IMPL(s, ...)                                         \
-  [] {                                                                  \
-    struct str : fmt::compile_string {                                  \
-      using char_type = typename std::remove_cv<std::remove_pointer<    \
-          typename std::decay<decltype(s)>::type>::type>::type;         \
-      __VA_ARGS__ FMT_CONSTEXPR                                         \
-      operator fmt::basic_string_view<char_type>() const {              \
-        return {s, sizeof(s) / sizeof(char_type) - 1};                  \
-      }                                                                 \
-    } result;                                                           \
-    /* Suppress Qt Creator warning about unused operator. */            \
-    (void)static_cast<fmt::basic_string_view<typename str::char_type>>( \
-        result);                                                        \
-    return result;                                                      \
+#define FMT_STRING_IMPL(s, ...)                                     \
+  [] {                                                              \
+    /* Use a macro-like name to avoid shadowing warnings. */        \
+    struct FMT_COMPILE_STRING : fmt::compile_string {               \
+      using char_type = fmt::remove_cvref_t<decltype(s[0])>;        \
+      FMT_MAYBE_UNUSED __VA_ARGS__ FMT_CONSTEXPR                    \
+      operator fmt::basic_string_view<char_type>() const {          \
+        return fmt::internal::compile_string_to_view<char_type>(s); \
+      }                                                             \
+    };                                                              \
+    return FMT_COMPILE_STRING();                                    \
   }()
 
 /**
   \rst
-  Constructs a compile-time format string.
+  Constructs a compile-time format string from a string literal *s*.
 
   **Example**::
 
index 44ba77f02869482fc40c07f4adcc454fef5bf016..9a9abf8d0a7384021eb3013e2ae4177f3bf975d5 100644 (file)
@@ -19,7 +19,7 @@ int format_float(char* buf, std::size_t size, const char* format, int precision,
         "fuzz mode - avoid large allocation inside snprintf");
 #endif
   // Suppress the warning about nonliteral format string.
-  auto snprintf_ptr = FMT_SNPRINTF;
+  int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF;
   return precision < 0 ? snprintf_ptr(buf, size, format, value)
                        : snprintf_ptr(buf, size, format, precision, value);
 }
@@ -121,7 +121,7 @@ template FMT_API char* internal::sprintf_format(long double,
                                                 internal::buffer<char>&,
                                                 sprintf_specs);
 
-template struct FMT_API internal::basic_data<void>;
+template struct FMT_INSTANTIATION_DEF_API internal::basic_data<void>;
 
 // Workaround a bug in MSVC2013 that prevents instantiation of format_float.
 int (*instantiate_format_float)(double, int, internal::float_specs,