Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-01-09 10:11:05

0001 // Formatting library for C++ - the base API for char/UTF-8
0002 //
0003 // Copyright (c) 2012 - present, Victor Zverovich
0004 // All rights reserved.
0005 //
0006 // For the license information refer to format.h.
0007 
0008 #ifndef FMT_BASE_H_
0009 #define FMT_BASE_H_
0010 
0011 #if defined(FMT_IMPORT_STD) && !defined(FMT_MODULE)
0012 #  define FMT_MODULE
0013 #endif
0014 
0015 #ifndef FMT_MODULE
0016 #  include <limits.h>  // CHAR_BIT
0017 #  include <stdio.h>   // FILE
0018 #  include <string.h>  // memcmp
0019 
0020 #  include <type_traits>  // std::enable_if
0021 #endif
0022 
0023 // The fmt library version in the form major * 10000 + minor * 100 + patch.
0024 #define FMT_VERSION 110200
0025 
0026 // Detect compiler versions.
0027 #if defined(__clang__) && !defined(__ibmxl__)
0028 #  define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
0029 #else
0030 #  define FMT_CLANG_VERSION 0
0031 #endif
0032 #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
0033 #  define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
0034 #else
0035 #  define FMT_GCC_VERSION 0
0036 #endif
0037 #if defined(__ICL)
0038 #  define FMT_ICC_VERSION __ICL
0039 #elif defined(__INTEL_COMPILER)
0040 #  define FMT_ICC_VERSION __INTEL_COMPILER
0041 #else
0042 #  define FMT_ICC_VERSION 0
0043 #endif
0044 #if defined(_MSC_VER)
0045 #  define FMT_MSC_VERSION _MSC_VER
0046 #else
0047 #  define FMT_MSC_VERSION 0
0048 #endif
0049 
0050 // Detect standard library versions.
0051 #ifdef _GLIBCXX_RELEASE
0052 #  define FMT_GLIBCXX_RELEASE _GLIBCXX_RELEASE
0053 #else
0054 #  define FMT_GLIBCXX_RELEASE 0
0055 #endif
0056 #ifdef _LIBCPP_VERSION
0057 #  define FMT_LIBCPP_VERSION _LIBCPP_VERSION
0058 #else
0059 #  define FMT_LIBCPP_VERSION 0
0060 #endif
0061 
0062 #ifdef _MSVC_LANG
0063 #  define FMT_CPLUSPLUS _MSVC_LANG
0064 #else
0065 #  define FMT_CPLUSPLUS __cplusplus
0066 #endif
0067 
0068 // Detect __has_*.
0069 #ifdef __has_feature
0070 #  define FMT_HAS_FEATURE(x) __has_feature(x)
0071 #else
0072 #  define FMT_HAS_FEATURE(x) 0
0073 #endif
0074 #ifdef __has_include
0075 #  define FMT_HAS_INCLUDE(x) __has_include(x)
0076 #else
0077 #  define FMT_HAS_INCLUDE(x) 0
0078 #endif
0079 #ifdef __has_builtin
0080 #  define FMT_HAS_BUILTIN(x) __has_builtin(x)
0081 #else
0082 #  define FMT_HAS_BUILTIN(x) 0
0083 #endif
0084 #ifdef __has_cpp_attribute
0085 #  define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
0086 #else
0087 #  define FMT_HAS_CPP_ATTRIBUTE(x) 0
0088 #endif
0089 
0090 #define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
0091   (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
0092 
0093 #define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
0094   (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
0095 
0096 // Detect C++14 relaxed constexpr.
0097 #ifdef FMT_USE_CONSTEXPR
0098 // Use the provided definition.
0099 #elif FMT_GCC_VERSION >= 702 && FMT_CPLUSPLUS >= 201402L
0100 // GCC only allows constexpr member functions in non-literal types since 7.2:
0101 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66297.
0102 #  define FMT_USE_CONSTEXPR 1
0103 #elif FMT_ICC_VERSION
0104 #  define FMT_USE_CONSTEXPR 0  // https://github.com/fmtlib/fmt/issues/1628
0105 #elif FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912
0106 #  define FMT_USE_CONSTEXPR 1
0107 #else
0108 #  define FMT_USE_CONSTEXPR 0
0109 #endif
0110 #if FMT_USE_CONSTEXPR
0111 #  define FMT_CONSTEXPR constexpr
0112 #else
0113 #  define FMT_CONSTEXPR
0114 #endif
0115 
0116 // Detect consteval, C++20 constexpr extensions and std::is_constant_evaluated.
0117 #if !defined(__cpp_lib_is_constant_evaluated)
0118 #  define FMT_USE_CONSTEVAL 0
0119 #elif FMT_CPLUSPLUS < 201709L
0120 #  define FMT_USE_CONSTEVAL 0
0121 #elif FMT_GLIBCXX_RELEASE && FMT_GLIBCXX_RELEASE < 10
0122 #  define FMT_USE_CONSTEVAL 0
0123 #elif FMT_LIBCPP_VERSION && FMT_LIBCPP_VERSION < 10000
0124 #  define FMT_USE_CONSTEVAL 0
0125 #elif defined(__apple_build_version__) && __apple_build_version__ < 14000029L
0126 #  define FMT_USE_CONSTEVAL 0  // consteval is broken in Apple clang < 14.
0127 #elif FMT_MSC_VERSION && FMT_MSC_VERSION < 1929
0128 #  define FMT_USE_CONSTEVAL 0  // consteval is broken in MSVC VS2019 < 16.10.
0129 #elif defined(__cpp_consteval)
0130 #  define FMT_USE_CONSTEVAL 1
0131 #elif FMT_GCC_VERSION >= 1002 || FMT_CLANG_VERSION >= 1101
0132 #  define FMT_USE_CONSTEVAL 1
0133 #else
0134 #  define FMT_USE_CONSTEVAL 0
0135 #endif
0136 #if FMT_USE_CONSTEVAL
0137 #  define FMT_CONSTEVAL consteval
0138 #  define FMT_CONSTEXPR20 constexpr
0139 #else
0140 #  define FMT_CONSTEVAL
0141 #  define FMT_CONSTEXPR20
0142 #endif
0143 
0144 // Check if exceptions are disabled.
0145 #ifdef FMT_USE_EXCEPTIONS
0146 // Use the provided definition.
0147 #elif defined(__GNUC__) && !defined(__EXCEPTIONS)
0148 #  define FMT_USE_EXCEPTIONS 0
0149 #elif defined(__clang__) && !defined(__cpp_exceptions)
0150 #  define FMT_USE_EXCEPTIONS 0
0151 #elif FMT_MSC_VERSION && !_HAS_EXCEPTIONS
0152 #  define FMT_USE_EXCEPTIONS 0
0153 #else
0154 #  define FMT_USE_EXCEPTIONS 1
0155 #endif
0156 #if FMT_USE_EXCEPTIONS
0157 #  define FMT_TRY try
0158 #  define FMT_CATCH(x) catch (x)
0159 #else
0160 #  define FMT_TRY if (true)
0161 #  define FMT_CATCH(x) if (false)
0162 #endif
0163 
0164 #ifdef FMT_NO_UNIQUE_ADDRESS
0165 // Use the provided definition.
0166 #elif FMT_CPLUSPLUS < 202002L
0167 // Not supported.
0168 #elif FMT_HAS_CPP_ATTRIBUTE(no_unique_address)
0169 #  define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]]
0170 // VS2019 v16.10 and later except clang-cl (https://reviews.llvm.org/D110485).
0171 #elif FMT_MSC_VERSION >= 1929 && !FMT_CLANG_VERSION
0172 #  define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
0173 #endif
0174 #ifndef FMT_NO_UNIQUE_ADDRESS
0175 #  define FMT_NO_UNIQUE_ADDRESS
0176 #endif
0177 
0178 #if FMT_HAS_CPP17_ATTRIBUTE(fallthrough)
0179 #  define FMT_FALLTHROUGH [[fallthrough]]
0180 #elif defined(__clang__)
0181 #  define FMT_FALLTHROUGH [[clang::fallthrough]]
0182 #elif FMT_GCC_VERSION >= 700 && \
0183     (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520)
0184 #  define FMT_FALLTHROUGH [[gnu::fallthrough]]
0185 #else
0186 #  define FMT_FALLTHROUGH
0187 #endif
0188 
0189 // Disable [[noreturn]] on MSVC/NVCC because of bogus unreachable code warnings.
0190 #if FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && !defined(__NVCC__)
0191 #  define FMT_NORETURN [[noreturn]]
0192 #else
0193 #  define FMT_NORETURN
0194 #endif
0195 
0196 #ifdef FMT_NODISCARD
0197 // Use the provided definition.
0198 #elif FMT_HAS_CPP17_ATTRIBUTE(nodiscard)
0199 #  define FMT_NODISCARD [[nodiscard]]
0200 #else
0201 #  define FMT_NODISCARD
0202 #endif
0203 
0204 #ifdef FMT_DEPRECATED
0205 // Use the provided definition.
0206 #elif FMT_HAS_CPP14_ATTRIBUTE(deprecated)
0207 #  define FMT_DEPRECATED [[deprecated]]
0208 #else
0209 #  define FMT_DEPRECATED /* deprecated */
0210 #endif
0211 
0212 #if FMT_GCC_VERSION || FMT_CLANG_VERSION
0213 #  define FMT_VISIBILITY(value) __attribute__((visibility(value)))
0214 #else
0215 #  define FMT_VISIBILITY(value)
0216 #endif
0217 
0218 // Detect pragmas.
0219 #define FMT_PRAGMA_IMPL(x) _Pragma(#x)
0220 #if FMT_GCC_VERSION >= 504 && !defined(__NVCOMPILER)
0221 // Workaround a _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884
0222 // and an nvhpc warning: https://github.com/fmtlib/fmt/pull/2582.
0223 #  define FMT_PRAGMA_GCC(x) FMT_PRAGMA_IMPL(GCC x)
0224 #else
0225 #  define FMT_PRAGMA_GCC(x)
0226 #endif
0227 #if FMT_CLANG_VERSION
0228 #  define FMT_PRAGMA_CLANG(x) FMT_PRAGMA_IMPL(clang x)
0229 #else
0230 #  define FMT_PRAGMA_CLANG(x)
0231 #endif
0232 #if FMT_MSC_VERSION
0233 #  define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__))
0234 #else
0235 #  define FMT_MSC_WARNING(...)
0236 #endif
0237 
0238 // Enable minimal optimizations for more compact code in debug mode.
0239 FMT_PRAGMA_GCC(push_options)
0240 #if !defined(__OPTIMIZE__) && !defined(__CUDACC__) && !defined(FMT_MODULE)
0241 FMT_PRAGMA_GCC(optimize("Og"))
0242 #  define FMT_GCC_OPTIMIZED
0243 #endif
0244 FMT_PRAGMA_CLANG(diagnostic push)
0245 
0246 #ifdef FMT_ALWAYS_INLINE
0247 // Use the provided definition.
0248 #elif FMT_GCC_VERSION || FMT_CLANG_VERSION
0249 #  define FMT_ALWAYS_INLINE inline __attribute__((always_inline))
0250 #else
0251 #  define FMT_ALWAYS_INLINE inline
0252 #endif
0253 // A version of FMT_ALWAYS_INLINE to prevent code bloat in debug mode.
0254 #if defined(NDEBUG) || defined(FMT_GCC_OPTIMIZED)
0255 #  define FMT_INLINE FMT_ALWAYS_INLINE
0256 #else
0257 #  define FMT_INLINE inline
0258 #endif
0259 
0260 #ifndef FMT_BEGIN_NAMESPACE
0261 #  define FMT_BEGIN_NAMESPACE \
0262     namespace fmt {           \
0263     inline namespace v11 {
0264 #  define FMT_END_NAMESPACE \
0265     }                       \
0266     }
0267 #endif
0268 
0269 #ifndef FMT_EXPORT
0270 #  define FMT_EXPORT
0271 #  define FMT_BEGIN_EXPORT
0272 #  define FMT_END_EXPORT
0273 #endif
0274 
0275 #ifdef _WIN32
0276 #  define FMT_WIN32 1
0277 #else
0278 #  define FMT_WIN32 0
0279 #endif
0280 
0281 #if !defined(FMT_HEADER_ONLY) && FMT_WIN32
0282 #  if defined(FMT_LIB_EXPORT)
0283 #    define FMT_API __declspec(dllexport)
0284 #  elif defined(FMT_SHARED)
0285 #    define FMT_API __declspec(dllimport)
0286 #  endif
0287 #elif defined(FMT_LIB_EXPORT) || defined(FMT_SHARED)
0288 #  define FMT_API FMT_VISIBILITY("default")
0289 #endif
0290 #ifndef FMT_API
0291 #  define FMT_API
0292 #endif
0293 
0294 #ifndef FMT_OPTIMIZE_SIZE
0295 #  define FMT_OPTIMIZE_SIZE 0
0296 #endif
0297 
0298 // FMT_BUILTIN_TYPE=0 may result in smaller library size at the cost of higher
0299 // per-call binary size by passing built-in types through the extension API.
0300 #ifndef FMT_BUILTIN_TYPES
0301 #  define FMT_BUILTIN_TYPES 1
0302 #endif
0303 
0304 #define FMT_APPLY_VARIADIC(expr) \
0305   using unused = int[];          \
0306   (void)unused { 0, (expr, 0)... }
0307 
0308 FMT_BEGIN_NAMESPACE
0309 
0310 // Implementations of enable_if_t and other metafunctions for older systems.
0311 template <bool B, typename T = void>
0312 using enable_if_t = typename std::enable_if<B, T>::type;
0313 template <bool B, typename T, typename F>
0314 using conditional_t = typename std::conditional<B, T, F>::type;
0315 template <bool B> using bool_constant = std::integral_constant<bool, B>;
0316 template <typename T>
0317 using remove_reference_t = typename std::remove_reference<T>::type;
0318 template <typename T>
0319 using remove_const_t = typename std::remove_const<T>::type;
0320 template <typename T>
0321 using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
0322 template <typename T>
0323 using make_unsigned_t = typename std::make_unsigned<T>::type;
0324 template <typename T>
0325 using underlying_t = typename std::underlying_type<T>::type;
0326 template <typename T> using decay_t = typename std::decay<T>::type;
0327 using nullptr_t = decltype(nullptr);
0328 
0329 #if (FMT_GCC_VERSION && FMT_GCC_VERSION < 500) || FMT_MSC_VERSION
0330 // A workaround for gcc 4.9 & MSVC v141 to make void_t work in a SFINAE context.
0331 template <typename...> struct void_t_impl {
0332   using type = void;
0333 };
0334 template <typename... T> using void_t = typename void_t_impl<T...>::type;
0335 #else
0336 template <typename...> using void_t = void;
0337 #endif
0338 
0339 struct monostate {
0340   constexpr monostate() {}
0341 };
0342 
0343 // An enable_if helper to be used in template parameters which results in much
0344 // shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
0345 // to workaround a bug in MSVC 2019 (see #1140 and #1186).
0346 #ifdef FMT_DOC
0347 #  define FMT_ENABLE_IF(...)
0348 #else
0349 #  define FMT_ENABLE_IF(...) fmt::enable_if_t<(__VA_ARGS__), int> = 0
0350 #endif
0351 
0352 template <typename T> constexpr auto min_of(T a, T b) -> T {
0353   return a < b ? a : b;
0354 }
0355 template <typename T> constexpr auto max_of(T a, T b) -> T {
0356   return a > b ? a : b;
0357 }
0358 
0359 namespace detail {
0360 // Suppresses "unused variable" warnings with the method described in
0361 // https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/.
0362 // (void)var does not work on many Intel compilers.
0363 template <typename... T> FMT_CONSTEXPR void ignore_unused(const T&...) {}
0364 
0365 constexpr auto is_constant_evaluated(bool default_value = false) noexcept
0366     -> bool {
0367 // Workaround for incompatibility between clang 14 and libstdc++ consteval-based
0368 // std::is_constant_evaluated: https://github.com/fmtlib/fmt/issues/3247.
0369 #if FMT_CPLUSPLUS >= 202002L && FMT_GLIBCXX_RELEASE >= 12 && \
0370     (FMT_CLANG_VERSION >= 1400 && FMT_CLANG_VERSION < 1500)
0371   ignore_unused(default_value);
0372   return __builtin_is_constant_evaluated();
0373 #elif defined(__cpp_lib_is_constant_evaluated)
0374   ignore_unused(default_value);
0375   return std::is_constant_evaluated();
0376 #else
0377   return default_value;
0378 #endif
0379 }
0380 
0381 // Suppresses "conditional expression is constant" warnings.
0382 template <typename T> FMT_ALWAYS_INLINE constexpr auto const_check(T val) -> T {
0383   return val;
0384 }
0385 
0386 FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
0387                                       const char* message);
0388 
0389 #if defined(FMT_ASSERT)
0390 // Use the provided definition.
0391 #elif defined(NDEBUG)
0392 // FMT_ASSERT is not empty to avoid -Wempty-body.
0393 #  define FMT_ASSERT(condition, message) \
0394     fmt::detail::ignore_unused((condition), (message))
0395 #else
0396 #  define FMT_ASSERT(condition, message)                                    \
0397     ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
0398          ? (void)0                                                          \
0399          : fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
0400 #endif
0401 
0402 #ifdef FMT_USE_INT128
0403 // Use the provided definition.
0404 #elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \
0405     !(FMT_CLANG_VERSION && FMT_MSC_VERSION)
0406 #  define FMT_USE_INT128 1
0407 using int128_opt = __int128_t;  // An optional native 128-bit integer.
0408 using uint128_opt = __uint128_t;
0409 inline auto map(int128_opt x) -> int128_opt { return x; }
0410 inline auto map(uint128_opt x) -> uint128_opt { return x; }
0411 #else
0412 #  define FMT_USE_INT128 0
0413 #endif
0414 #if !FMT_USE_INT128
0415 enum class int128_opt {};
0416 enum class uint128_opt {};
0417 // Reduce template instantiations.
0418 inline auto map(int128_opt) -> monostate { return {}; }
0419 inline auto map(uint128_opt) -> monostate { return {}; }
0420 #endif
0421 
0422 #ifndef FMT_USE_BITINT
0423 #  define FMT_USE_BITINT (FMT_CLANG_VERSION >= 1500)
0424 #endif
0425 
0426 #if FMT_USE_BITINT
0427 FMT_PRAGMA_CLANG(diagnostic ignored "-Wbit-int-extension")
0428 template <int N> using bitint = _BitInt(N);
0429 template <int N> using ubitint = unsigned _BitInt(N);
0430 #else
0431 template <int N> struct bitint {};
0432 template <int N> struct ubitint {};
0433 #endif  // FMT_USE_BITINT
0434 
0435 // Casts a nonnegative integer to unsigned.
0436 template <typename Int>
0437 FMT_CONSTEXPR auto to_unsigned(Int value) -> make_unsigned_t<Int> {
0438   FMT_ASSERT(std::is_unsigned<Int>::value || value >= 0, "negative value");
0439   return static_cast<make_unsigned_t<Int>>(value);
0440 }
0441 
0442 template <typename Char>
0443 using unsigned_char = conditional_t<sizeof(Char) == 1, unsigned char, unsigned>;
0444 
0445 // A heuristic to detect std::string and std::[experimental::]string_view.
0446 // It is mainly used to avoid dependency on <[experimental/]string_view>.
0447 template <typename T, typename Enable = void>
0448 struct is_std_string_like : std::false_type {};
0449 template <typename T>
0450 struct is_std_string_like<T, void_t<decltype(std::declval<T>().find_first_of(
0451                                  typename T::value_type(), 0))>>
0452     : std::is_convertible<decltype(std::declval<T>().data()),
0453                           const typename T::value_type*> {};
0454 
0455 // Check if the literal encoding is UTF-8.
0456 enum { is_utf8_enabled = "\u00A7"[1] == '\xA7' };
0457 enum { use_utf8 = !FMT_WIN32 || is_utf8_enabled };
0458 
0459 #ifndef FMT_UNICODE
0460 #  define FMT_UNICODE 1
0461 #endif
0462 
0463 static_assert(!FMT_UNICODE || use_utf8,
0464               "Unicode support requires compiling with /utf-8");
0465 
0466 template <typename T> constexpr const char* narrow(const T*) { return nullptr; }
0467 constexpr FMT_ALWAYS_INLINE const char* narrow(const char* s) { return s; }
0468 
0469 template <typename Char>
0470 FMT_CONSTEXPR auto compare(const Char* s1, const Char* s2, std::size_t n)
0471     -> int {
0472   if (!is_constant_evaluated() && sizeof(Char) == 1) return memcmp(s1, s2, n);
0473   for (; n != 0; ++s1, ++s2, --n) {
0474     if (*s1 < *s2) return -1;
0475     if (*s1 > *s2) return 1;
0476   }
0477   return 0;
0478 }
0479 
0480 namespace adl {
0481 using namespace std;
0482 
0483 template <typename Container>
0484 auto invoke_back_inserter()
0485     -> decltype(back_inserter(std::declval<Container&>()));
0486 }  // namespace adl
0487 
0488 template <typename It, typename Enable = std::true_type>
0489 struct is_back_insert_iterator : std::false_type {};
0490 
0491 template <typename It>
0492 struct is_back_insert_iterator<
0493     It, bool_constant<std::is_same<
0494             decltype(adl::invoke_back_inserter<typename It::container_type>()),
0495             It>::value>> : std::true_type {};
0496 
0497 // Extracts a reference to the container from *insert_iterator.
0498 template <typename OutputIt>
0499 inline FMT_CONSTEXPR20 auto get_container(OutputIt it) ->
0500     typename OutputIt::container_type& {
0501   struct accessor : OutputIt {
0502     FMT_CONSTEXPR20 accessor(OutputIt base) : OutputIt(base) {}
0503     using OutputIt::container;
0504   };
0505   return *accessor(it).container;
0506 }
0507 }  // namespace detail
0508 
0509 // Parsing-related public API and forward declarations.
0510 FMT_BEGIN_EXPORT
0511 
0512 /**
0513  * An implementation of `std::basic_string_view` for pre-C++17. It provides a
0514  * subset of the API. `fmt::basic_string_view` is used for format strings even
0515  * if `std::basic_string_view` is available to prevent issues when a library is
0516  * compiled with a different `-std` option than the client code (which is not
0517  * recommended).
0518  */
0519 template <typename Char> class basic_string_view {
0520  private:
0521   const Char* data_;
0522   size_t size_;
0523 
0524  public:
0525   using value_type = Char;
0526   using iterator = const Char*;
0527 
0528   constexpr basic_string_view() noexcept : data_(nullptr), size_(0) {}
0529 
0530   /// Constructs a string view object from a C string and a size.
0531   constexpr basic_string_view(const Char* s, size_t count) noexcept
0532       : data_(s), size_(count) {}
0533 
0534   constexpr basic_string_view(nullptr_t) = delete;
0535 
0536   /// Constructs a string view object from a C string.
0537 #if FMT_GCC_VERSION
0538   FMT_ALWAYS_INLINE
0539 #endif
0540   FMT_CONSTEXPR20 basic_string_view(const Char* s) : data_(s) {
0541 #if FMT_HAS_BUILTIN(__builtin_strlen) || FMT_GCC_VERSION || FMT_CLANG_VERSION
0542     if (std::is_same<Char, char>::value && !detail::is_constant_evaluated()) {
0543       size_ = __builtin_strlen(detail::narrow(s));  // strlen is not costexpr.
0544       return;
0545     }
0546 #endif
0547     size_t len = 0;
0548     while (*s++) ++len;
0549     size_ = len;
0550   }
0551 
0552   /// Constructs a string view from a `std::basic_string` or a
0553   /// `std::basic_string_view` object.
0554   template <typename S,
0555             FMT_ENABLE_IF(detail::is_std_string_like<S>::value&& std::is_same<
0556                           typename S::value_type, Char>::value)>
0557   FMT_CONSTEXPR basic_string_view(const S& s) noexcept
0558       : data_(s.data()), size_(s.size()) {}
0559 
0560   /// Returns a pointer to the string data.
0561   constexpr auto data() const noexcept -> const Char* { return data_; }
0562 
0563   /// Returns the string size.
0564   constexpr auto size() const noexcept -> size_t { return size_; }
0565 
0566   constexpr auto begin() const noexcept -> iterator { return data_; }
0567   constexpr auto end() const noexcept -> iterator { return data_ + size_; }
0568 
0569   constexpr auto operator[](size_t pos) const noexcept -> const Char& {
0570     return data_[pos];
0571   }
0572 
0573   FMT_CONSTEXPR void remove_prefix(size_t n) noexcept {
0574     data_ += n;
0575     size_ -= n;
0576   }
0577 
0578   FMT_CONSTEXPR auto starts_with(basic_string_view<Char> sv) const noexcept
0579       -> bool {
0580     return size_ >= sv.size_ && detail::compare(data_, sv.data_, sv.size_) == 0;
0581   }
0582   FMT_CONSTEXPR auto starts_with(Char c) const noexcept -> bool {
0583     return size_ >= 1 && *data_ == c;
0584   }
0585   FMT_CONSTEXPR auto starts_with(const Char* s) const -> bool {
0586     return starts_with(basic_string_view<Char>(s));
0587   }
0588 
0589   FMT_CONSTEXPR auto compare(basic_string_view other) const -> int {
0590     int result =
0591         detail::compare(data_, other.data_, min_of(size_, other.size_));
0592     if (result != 0) return result;
0593     return size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
0594   }
0595 
0596   FMT_CONSTEXPR friend auto operator==(basic_string_view lhs,
0597                                        basic_string_view rhs) -> bool {
0598     return lhs.compare(rhs) == 0;
0599   }
0600   friend auto operator!=(basic_string_view lhs, basic_string_view rhs) -> bool {
0601     return lhs.compare(rhs) != 0;
0602   }
0603   friend auto operator<(basic_string_view lhs, basic_string_view rhs) -> bool {
0604     return lhs.compare(rhs) < 0;
0605   }
0606   friend auto operator<=(basic_string_view lhs, basic_string_view rhs) -> bool {
0607     return lhs.compare(rhs) <= 0;
0608   }
0609   friend auto operator>(basic_string_view lhs, basic_string_view rhs) -> bool {
0610     return lhs.compare(rhs) > 0;
0611   }
0612   friend auto operator>=(basic_string_view lhs, basic_string_view rhs) -> bool {
0613     return lhs.compare(rhs) >= 0;
0614   }
0615 };
0616 
0617 using string_view = basic_string_view<char>;
0618 
0619 // DEPRECATED! Will be merged with is_char and moved to detail.
0620 template <typename T> struct is_xchar : std::false_type {};
0621 template <> struct is_xchar<wchar_t> : std::true_type {};
0622 template <> struct is_xchar<char16_t> : std::true_type {};
0623 template <> struct is_xchar<char32_t> : std::true_type {};
0624 #ifdef __cpp_char8_t
0625 template <> struct is_xchar<char8_t> : std::true_type {};
0626 #endif
0627 
0628 // Specifies if `T` is a character (code unit) type.
0629 template <typename T> struct is_char : is_xchar<T> {};
0630 template <> struct is_char<char> : std::true_type {};
0631 
0632 template <typename T> class basic_appender;
0633 using appender = basic_appender<char>;
0634 
0635 // Checks whether T is a container with contiguous storage.
0636 template <typename T> struct is_contiguous : std::false_type {};
0637 
0638 class context;
0639 template <typename OutputIt, typename Char> class generic_context;
0640 template <typename Char> class parse_context;
0641 
0642 // Longer aliases for C++20 compatibility.
0643 template <typename Char> using basic_format_parse_context = parse_context<Char>;
0644 using format_parse_context = parse_context<char>;
0645 template <typename OutputIt, typename Char>
0646 using basic_format_context =
0647     conditional_t<std::is_same<OutputIt, appender>::value, context,
0648                   generic_context<OutputIt, Char>>;
0649 using format_context = context;
0650 
0651 template <typename Char>
0652 using buffered_context =
0653     conditional_t<std::is_same<Char, char>::value, context,
0654                   generic_context<basic_appender<Char>, Char>>;
0655 
0656 template <typename Context> class basic_format_arg;
0657 template <typename Context> class basic_format_args;
0658 
0659 // A separate type would result in shorter symbols but break ABI compatibility
0660 // between clang and gcc on ARM (#1919).
0661 using format_args = basic_format_args<context>;
0662 
0663 // A formatter for objects of type T.
0664 template <typename T, typename Char = char, typename Enable = void>
0665 struct formatter {
0666   // A deleted default constructor indicates a disabled formatter.
0667   formatter() = delete;
0668 };
0669 
0670 /// Reports a format error at compile time or, via a `format_error` exception,
0671 /// at runtime.
0672 // This function is intentionally not constexpr to give a compile-time error.
0673 FMT_NORETURN FMT_API void report_error(const char* message);
0674 
0675 enum class presentation_type : unsigned char {
0676   // Common specifiers:
0677   none = 0,
0678   debug = 1,   // '?'
0679   string = 2,  // 's' (string, bool)
0680 
0681   // Integral, bool and character specifiers:
0682   dec = 3,  // 'd'
0683   hex,      // 'x' or 'X'
0684   oct,      // 'o'
0685   bin,      // 'b' or 'B'
0686   chr,      // 'c'
0687 
0688   // String and pointer specifiers:
0689   pointer = 3,  // 'p'
0690 
0691   // Floating-point specifiers:
0692   exp = 1,  // 'e' or 'E' (1 since there is no FP debug presentation)
0693   fixed,    // 'f' or 'F'
0694   general,  // 'g' or 'G'
0695   hexfloat  // 'a' or 'A'
0696 };
0697 
0698 enum class align { none, left, right, center, numeric };
0699 enum class sign { none, minus, plus, space };
0700 enum class arg_id_kind { none, index, name };
0701 
0702 // Basic format specifiers for built-in and string types.
0703 class basic_specs {
0704  private:
0705   // Data is arranged as follows:
0706   //
0707   //  0                   1                   2                   3
0708   //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
0709   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0710   // |type |align| w | p | s |u|#|L|  f  |          unused           |
0711   // +-----+-----+---+---+---+-+-+-+-----+---------------------------+
0712   //
0713   //   w - dynamic width info
0714   //   p - dynamic precision info
0715   //   s - sign
0716   //   u - uppercase (e.g. 'X' for 'x')
0717   //   # - alternate form ('#')
0718   //   L - localized
0719   //   f - fill size
0720   //
0721   // Bitfields are not used because of compiler bugs such as gcc bug 61414.
0722   enum : unsigned {
0723     type_mask = 0x00007,
0724     align_mask = 0x00038,
0725     width_mask = 0x000C0,
0726     precision_mask = 0x00300,
0727     sign_mask = 0x00C00,
0728     uppercase_mask = 0x01000,
0729     alternate_mask = 0x02000,
0730     localized_mask = 0x04000,
0731     fill_size_mask = 0x38000,
0732 
0733     align_shift = 3,
0734     width_shift = 6,
0735     precision_shift = 8,
0736     sign_shift = 10,
0737     fill_size_shift = 15,
0738 
0739     max_fill_size = 4
0740   };
0741 
0742   unsigned data_ = 1 << fill_size_shift;
0743   static_assert(sizeof(basic_specs::data_) * CHAR_BIT >= 18, "");
0744 
0745   // Character (code unit) type is erased to prevent template bloat.
0746   char fill_data_[max_fill_size] = {' '};
0747 
0748   FMT_CONSTEXPR void set_fill_size(size_t size) {
0749     data_ = (data_ & ~fill_size_mask) |
0750             (static_cast<unsigned>(size) << fill_size_shift);
0751   }
0752 
0753  public:
0754   constexpr auto type() const -> presentation_type {
0755     return static_cast<presentation_type>(data_ & type_mask);
0756   }
0757   FMT_CONSTEXPR void set_type(presentation_type t) {
0758     data_ = (data_ & ~type_mask) | static_cast<unsigned>(t);
0759   }
0760 
0761   constexpr auto align() const -> align {
0762     return static_cast<fmt::align>((data_ & align_mask) >> align_shift);
0763   }
0764   FMT_CONSTEXPR void set_align(fmt::align a) {
0765     data_ = (data_ & ~align_mask) | (static_cast<unsigned>(a) << align_shift);
0766   }
0767 
0768   constexpr auto dynamic_width() const -> arg_id_kind {
0769     return static_cast<arg_id_kind>((data_ & width_mask) >> width_shift);
0770   }
0771   FMT_CONSTEXPR void set_dynamic_width(arg_id_kind w) {
0772     data_ = (data_ & ~width_mask) | (static_cast<unsigned>(w) << width_shift);
0773   }
0774 
0775   FMT_CONSTEXPR auto dynamic_precision() const -> arg_id_kind {
0776     return static_cast<arg_id_kind>((data_ & precision_mask) >>
0777                                     precision_shift);
0778   }
0779   FMT_CONSTEXPR void set_dynamic_precision(arg_id_kind p) {
0780     data_ = (data_ & ~precision_mask) |
0781             (static_cast<unsigned>(p) << precision_shift);
0782   }
0783 
0784   constexpr bool dynamic() const {
0785     return (data_ & (width_mask | precision_mask)) != 0;
0786   }
0787 
0788   constexpr auto sign() const -> sign {
0789     return static_cast<fmt::sign>((data_ & sign_mask) >> sign_shift);
0790   }
0791   FMT_CONSTEXPR void set_sign(fmt::sign s) {
0792     data_ = (data_ & ~sign_mask) | (static_cast<unsigned>(s) << sign_shift);
0793   }
0794 
0795   constexpr auto upper() const -> bool { return (data_ & uppercase_mask) != 0; }
0796   FMT_CONSTEXPR void set_upper() { data_ |= uppercase_mask; }
0797 
0798   constexpr auto alt() const -> bool { return (data_ & alternate_mask) != 0; }
0799   FMT_CONSTEXPR void set_alt() { data_ |= alternate_mask; }
0800   FMT_CONSTEXPR void clear_alt() { data_ &= ~alternate_mask; }
0801 
0802   constexpr auto localized() const -> bool {
0803     return (data_ & localized_mask) != 0;
0804   }
0805   FMT_CONSTEXPR void set_localized() { data_ |= localized_mask; }
0806 
0807   constexpr auto fill_size() const -> size_t {
0808     return (data_ & fill_size_mask) >> fill_size_shift;
0809   }
0810 
0811   template <typename Char, FMT_ENABLE_IF(std::is_same<Char, char>::value)>
0812   constexpr auto fill() const -> const Char* {
0813     return fill_data_;
0814   }
0815   template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
0816   constexpr auto fill() const -> const Char* {
0817     return nullptr;
0818   }
0819 
0820   template <typename Char> constexpr auto fill_unit() const -> Char {
0821     using uchar = unsigned char;
0822     return static_cast<Char>(static_cast<uchar>(fill_data_[0]) |
0823                              (static_cast<uchar>(fill_data_[1]) << 8) |
0824                              (static_cast<uchar>(fill_data_[2]) << 16));
0825   }
0826 
0827   FMT_CONSTEXPR void set_fill(char c) {
0828     fill_data_[0] = c;
0829     set_fill_size(1);
0830   }
0831 
0832   template <typename Char>
0833   FMT_CONSTEXPR void set_fill(basic_string_view<Char> s) {
0834     auto size = s.size();
0835     set_fill_size(size);
0836     if (size == 1) {
0837       unsigned uchar = static_cast<detail::unsigned_char<Char>>(s[0]);
0838       fill_data_[0] = static_cast<char>(uchar);
0839       fill_data_[1] = static_cast<char>(uchar >> 8);
0840       fill_data_[2] = static_cast<char>(uchar >> 16);
0841       return;
0842     }
0843     FMT_ASSERT(size <= max_fill_size, "invalid fill");
0844     for (size_t i = 0; i < size; ++i)
0845       fill_data_[i & 3] = static_cast<char>(s[i]);
0846   }
0847 
0848   FMT_CONSTEXPR void copy_fill_from(const basic_specs& specs) {
0849     set_fill_size(specs.fill_size());
0850     for (size_t i = 0; i < max_fill_size; ++i)
0851       fill_data_[i] = specs.fill_data_[i];
0852   }
0853 };
0854 
0855 // Format specifiers for built-in and string types.
0856 struct format_specs : basic_specs {
0857   int width;
0858   int precision;
0859 
0860   constexpr format_specs() : width(0), precision(-1) {}
0861 };
0862 
0863 /**
0864  * Parsing context consisting of a format string range being parsed and an
0865  * argument counter for automatic indexing.
0866  */
0867 template <typename Char = char> class parse_context {
0868  private:
0869   basic_string_view<Char> fmt_;
0870   int next_arg_id_;
0871 
0872   enum { use_constexpr_cast = !FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200 };
0873 
0874   FMT_CONSTEXPR void do_check_arg_id(int arg_id);
0875 
0876  public:
0877   using char_type = Char;
0878   using iterator = const Char*;
0879 
0880   constexpr explicit parse_context(basic_string_view<Char> fmt,
0881                                    int next_arg_id = 0)
0882       : fmt_(fmt), next_arg_id_(next_arg_id) {}
0883 
0884   /// Returns an iterator to the beginning of the format string range being
0885   /// parsed.
0886   constexpr auto begin() const noexcept -> iterator { return fmt_.begin(); }
0887 
0888   /// Returns an iterator past the end of the format string range being parsed.
0889   constexpr auto end() const noexcept -> iterator { return fmt_.end(); }
0890 
0891   /// Advances the begin iterator to `it`.
0892   FMT_CONSTEXPR void advance_to(iterator it) {
0893     fmt_.remove_prefix(detail::to_unsigned(it - begin()));
0894   }
0895 
0896   /// Reports an error if using the manual argument indexing; otherwise returns
0897   /// the next argument index and switches to the automatic indexing.
0898   FMT_CONSTEXPR auto next_arg_id() -> int {
0899     if (next_arg_id_ < 0) {
0900       report_error("cannot switch from manual to automatic argument indexing");
0901       return 0;
0902     }
0903     int id = next_arg_id_++;
0904     do_check_arg_id(id);
0905     return id;
0906   }
0907 
0908   /// Reports an error if using the automatic argument indexing; otherwise
0909   /// switches to the manual indexing.
0910   FMT_CONSTEXPR void check_arg_id(int id) {
0911     if (next_arg_id_ > 0) {
0912       report_error("cannot switch from automatic to manual argument indexing");
0913       return;
0914     }
0915     next_arg_id_ = -1;
0916     do_check_arg_id(id);
0917   }
0918   FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {
0919     next_arg_id_ = -1;
0920   }
0921   FMT_CONSTEXPR void check_dynamic_spec(int arg_id);
0922 };
0923 
0924 FMT_END_EXPORT
0925 
0926 namespace detail {
0927 
0928 // Constructs fmt::basic_string_view<Char> from types implicitly convertible
0929 // to it, deducing Char. Explicitly convertible types such as the ones returned
0930 // from FMT_STRING are intentionally excluded.
0931 template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
0932 constexpr auto to_string_view(const Char* s) -> basic_string_view<Char> {
0933   return s;
0934 }
0935 template <typename T, FMT_ENABLE_IF(is_std_string_like<T>::value)>
0936 constexpr auto to_string_view(const T& s)
0937     -> basic_string_view<typename T::value_type> {
0938   return s;
0939 }
0940 template <typename Char>
0941 constexpr auto to_string_view(basic_string_view<Char> s)
0942     -> basic_string_view<Char> {
0943   return s;
0944 }
0945 
0946 template <typename T, typename Enable = void>
0947 struct has_to_string_view : std::false_type {};
0948 // detail:: is intentional since to_string_view is not an extension point.
0949 template <typename T>
0950 struct has_to_string_view<
0951     T, void_t<decltype(detail::to_string_view(std::declval<T>()))>>
0952     : std::true_type {};
0953 
0954 /// String's character (code unit) type. detail:: is intentional to prevent ADL.
0955 template <typename S,
0956           typename V = decltype(detail::to_string_view(std::declval<S>()))>
0957 using char_t = typename V::value_type;
0958 
0959 enum class type {
0960   none_type,
0961   // Integer types should go first,
0962   int_type,
0963   uint_type,
0964   long_long_type,
0965   ulong_long_type,
0966   int128_type,
0967   uint128_type,
0968   bool_type,
0969   char_type,
0970   last_integer_type = char_type,
0971   // followed by floating-point types.
0972   float_type,
0973   double_type,
0974   long_double_type,
0975   last_numeric_type = long_double_type,
0976   cstring_type,
0977   string_type,
0978   pointer_type,
0979   custom_type
0980 };
0981 
0982 // Maps core type T to the corresponding type enum constant.
0983 template <typename T, typename Char>
0984 struct type_constant : std::integral_constant<type, type::custom_type> {};
0985 
0986 #define FMT_TYPE_CONSTANT(Type, constant) \
0987   template <typename Char>                \
0988   struct type_constant<Type, Char>        \
0989       : std::integral_constant<type, type::constant> {}
0990 
0991 FMT_TYPE_CONSTANT(int, int_type);
0992 FMT_TYPE_CONSTANT(unsigned, uint_type);
0993 FMT_TYPE_CONSTANT(long long, long_long_type);
0994 FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
0995 FMT_TYPE_CONSTANT(int128_opt, int128_type);
0996 FMT_TYPE_CONSTANT(uint128_opt, uint128_type);
0997 FMT_TYPE_CONSTANT(bool, bool_type);
0998 FMT_TYPE_CONSTANT(Char, char_type);
0999 FMT_TYPE_CONSTANT(float, float_type);
1000 FMT_TYPE_CONSTANT(double, double_type);
1001 FMT_TYPE_CONSTANT(long double, long_double_type);
1002 FMT_TYPE_CONSTANT(const Char*, cstring_type);
1003 FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
1004 FMT_TYPE_CONSTANT(const void*, pointer_type);
1005 
1006 constexpr auto is_integral_type(type t) -> bool {
1007   return t > type::none_type && t <= type::last_integer_type;
1008 }
1009 constexpr auto is_arithmetic_type(type t) -> bool {
1010   return t > type::none_type && t <= type::last_numeric_type;
1011 }
1012 
1013 constexpr auto set(type rhs) -> int { return 1 << static_cast<int>(rhs); }
1014 constexpr auto in(type t, int set) -> bool {
1015   return ((set >> static_cast<int>(t)) & 1) != 0;
1016 }
1017 
1018 // Bitsets of types.
1019 enum {
1020   sint_set =
1021       set(type::int_type) | set(type::long_long_type) | set(type::int128_type),
1022   uint_set = set(type::uint_type) | set(type::ulong_long_type) |
1023              set(type::uint128_type),
1024   bool_set = set(type::bool_type),
1025   char_set = set(type::char_type),
1026   float_set = set(type::float_type) | set(type::double_type) |
1027               set(type::long_double_type),
1028   string_set = set(type::string_type),
1029   cstring_set = set(type::cstring_type),
1030   pointer_set = set(type::pointer_type)
1031 };
1032 
1033 struct view {};
1034 
1035 template <typename T, typename Enable = std::true_type>
1036 struct is_view : std::false_type {};
1037 template <typename T>
1038 struct is_view<T, bool_constant<sizeof(T) != 0>> : std::is_base_of<view, T> {};
1039 
1040 template <typename Char, typename T> struct named_arg;
1041 template <typename T> struct is_named_arg : std::false_type {};
1042 template <typename T> struct is_static_named_arg : std::false_type {};
1043 
1044 template <typename Char, typename T>
1045 struct is_named_arg<named_arg<Char, T>> : std::true_type {};
1046 
1047 template <typename Char, typename T> struct named_arg : view {
1048   const Char* name;
1049   const T& value;
1050 
1051   named_arg(const Char* n, const T& v) : name(n), value(v) {}
1052   static_assert(!is_named_arg<T>::value, "nested named arguments");
1053 };
1054 
1055 template <bool B = false> constexpr auto count() -> int { return B ? 1 : 0; }
1056 template <bool B1, bool B2, bool... Tail> constexpr auto count() -> int {
1057   return (B1 ? 1 : 0) + count<B2, Tail...>();
1058 }
1059 
1060 template <typename... Args> constexpr auto count_named_args() -> int {
1061   return count<is_named_arg<Args>::value...>();
1062 }
1063 template <typename... Args> constexpr auto count_static_named_args() -> int {
1064   return count<is_static_named_arg<Args>::value...>();
1065 }
1066 
1067 template <typename Char> struct named_arg_info {
1068   const Char* name;
1069   int id;
1070 };
1071 
1072 // named_args is non-const to suppress a bogus -Wmaybe-uninitalized in gcc 13.
1073 template <typename Char>
1074 FMT_CONSTEXPR void check_for_duplicate(named_arg_info<Char>* named_args,
1075                                        int named_arg_index,
1076                                        basic_string_view<Char> arg_name) {
1077   for (int i = 0; i < named_arg_index; ++i) {
1078     if (named_args[i].name == arg_name) report_error("duplicate named arg");
1079   }
1080 }
1081 
1082 template <typename Char, typename T, FMT_ENABLE_IF(!is_named_arg<T>::value)>
1083 void init_named_arg(named_arg_info<Char>*, int& arg_index, int&, const T&) {
1084   ++arg_index;
1085 }
1086 template <typename Char, typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
1087 void init_named_arg(named_arg_info<Char>* named_args, int& arg_index,
1088                     int& named_arg_index, const T& arg) {
1089   check_for_duplicate<Char>(named_args, named_arg_index, arg.name);
1090   named_args[named_arg_index++] = {arg.name, arg_index++};
1091 }
1092 
1093 template <typename T, typename Char,
1094           FMT_ENABLE_IF(!is_static_named_arg<T>::value)>
1095 FMT_CONSTEXPR void init_static_named_arg(named_arg_info<Char>*, int& arg_index,
1096                                          int&) {
1097   ++arg_index;
1098 }
1099 template <typename T, typename Char,
1100           FMT_ENABLE_IF(is_static_named_arg<T>::value)>
1101 FMT_CONSTEXPR void init_static_named_arg(named_arg_info<Char>* named_args,
1102                                          int& arg_index, int& named_arg_index) {
1103   check_for_duplicate<Char>(named_args, named_arg_index, T::name);
1104   named_args[named_arg_index++] = {T::name, arg_index++};
1105 }
1106 
1107 // To minimize the number of types we need to deal with, long is translated
1108 // either to int or to long long depending on its size.
1109 enum { long_short = sizeof(long) == sizeof(int) && FMT_BUILTIN_TYPES };
1110 using long_type = conditional_t<long_short, int, long long>;
1111 using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
1112 
1113 template <typename T>
1114 using format_as_result =
1115     remove_cvref_t<decltype(format_as(std::declval<const T&>()))>;
1116 template <typename T>
1117 using format_as_member_result =
1118     remove_cvref_t<decltype(formatter<T>::format_as(std::declval<const T&>()))>;
1119 
1120 template <typename T, typename Enable = std::true_type>
1121 struct use_format_as : std::false_type {};
1122 // format_as member is only used to avoid injection into the std namespace.
1123 template <typename T, typename Enable = std::true_type>
1124 struct use_format_as_member : std::false_type {};
1125 
1126 // Only map owning types because mapping views can be unsafe.
1127 template <typename T>
1128 struct use_format_as<
1129     T, bool_constant<std::is_arithmetic<format_as_result<T>>::value>>
1130     : std::true_type {};
1131 template <typename T>
1132 struct use_format_as_member<
1133     T, bool_constant<std::is_arithmetic<format_as_member_result<T>>::value>>
1134     : std::true_type {};
1135 
1136 template <typename T, typename U = remove_const_t<T>>
1137 using use_formatter =
1138     bool_constant<(std::is_class<T>::value || std::is_enum<T>::value ||
1139                    std::is_union<T>::value || std::is_array<T>::value) &&
1140                   !has_to_string_view<T>::value && !is_named_arg<T>::value &&
1141                   !use_format_as<T>::value && !use_format_as_member<U>::value>;
1142 
1143 template <typename Char, typename T, typename U = remove_const_t<T>>
1144 auto has_formatter_impl(T* p, buffered_context<Char>* ctx = nullptr)
1145     -> decltype(formatter<U, Char>().format(*p, *ctx), std::true_type());
1146 template <typename Char> auto has_formatter_impl(...) -> std::false_type;
1147 
1148 // T can be const-qualified to check if it is const-formattable.
1149 template <typename T, typename Char> constexpr auto has_formatter() -> bool {
1150   return decltype(has_formatter_impl<Char>(static_cast<T*>(nullptr)))::value;
1151 }
1152 
1153 // Maps formatting argument types to natively supported types or user-defined
1154 // types with formatters. Returns void on errors to be SFINAE-friendly.
1155 template <typename Char> struct type_mapper {
1156   static auto map(signed char) -> int;
1157   static auto map(unsigned char) -> unsigned;
1158   static auto map(short) -> int;
1159   static auto map(unsigned short) -> unsigned;
1160   static auto map(int) -> int;
1161   static auto map(unsigned) -> unsigned;
1162   static auto map(long) -> long_type;
1163   static auto map(unsigned long) -> ulong_type;
1164   static auto map(long long) -> long long;
1165   static auto map(unsigned long long) -> unsigned long long;
1166   static auto map(int128_opt) -> int128_opt;
1167   static auto map(uint128_opt) -> uint128_opt;
1168   static auto map(bool) -> bool;
1169 
1170   template <int N>
1171   static auto map(bitint<N>) -> conditional_t<N <= 64, long long, void>;
1172   template <int N>
1173   static auto map(ubitint<N>)
1174       -> conditional_t<N <= 64, unsigned long long, void>;
1175 
1176   template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
1177   static auto map(T) -> conditional_t<
1178       std::is_same<T, char>::value || std::is_same<T, Char>::value, Char, void>;
1179 
1180   static auto map(float) -> float;
1181   static auto map(double) -> double;
1182   static auto map(long double) -> long double;
1183 
1184   static auto map(Char*) -> const Char*;
1185   static auto map(const Char*) -> const Char*;
1186   template <typename T, typename C = char_t<T>,
1187             FMT_ENABLE_IF(!std::is_pointer<T>::value)>
1188   static auto map(const T&) -> conditional_t<std::is_same<C, Char>::value,
1189                                              basic_string_view<C>, void>;
1190 
1191   static auto map(void*) -> const void*;
1192   static auto map(const void*) -> const void*;
1193   static auto map(volatile void*) -> const void*;
1194   static auto map(const volatile void*) -> const void*;
1195   static auto map(nullptr_t) -> const void*;
1196   template <typename T, FMT_ENABLE_IF(std::is_pointer<T>::value ||
1197                                       std::is_member_pointer<T>::value)>
1198   static auto map(const T&) -> void;
1199 
1200   template <typename T, FMT_ENABLE_IF(use_format_as<T>::value)>
1201   static auto map(const T& x) -> decltype(map(format_as(x)));
1202   template <typename T, FMT_ENABLE_IF(use_format_as_member<T>::value)>
1203   static auto map(const T& x) -> decltype(map(formatter<T>::format_as(x)));
1204 
1205   template <typename T, FMT_ENABLE_IF(use_formatter<T>::value)>
1206   static auto map(T&) -> conditional_t<has_formatter<T, Char>(), T&, void>;
1207 
1208   template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
1209   static auto map(const T& named_arg) -> decltype(map(named_arg.value));
1210 };
1211 
1212 // detail:: is used to workaround a bug in MSVC 2017.
1213 template <typename T, typename Char>
1214 using mapped_t = decltype(detail::type_mapper<Char>::map(std::declval<T&>()));
1215 
1216 // A type constant after applying type_mapper.
1217 template <typename T, typename Char = char>
1218 using mapped_type_constant = type_constant<mapped_t<T, Char>, Char>;
1219 
1220 template <typename T, typename Context,
1221           type TYPE =
1222               mapped_type_constant<T, typename Context::char_type>::value>
1223 using stored_type_constant = std::integral_constant<
1224     type, Context::builtin_types || TYPE == type::int_type ? TYPE
1225                                                            : type::custom_type>;
1226 // A parse context with extra data used only in compile-time checks.
1227 template <typename Char>
1228 class compile_parse_context : public parse_context<Char> {
1229  private:
1230   int num_args_;
1231   const type* types_;
1232   using base = parse_context<Char>;
1233 
1234  public:
1235   FMT_CONSTEXPR explicit compile_parse_context(basic_string_view<Char> fmt,
1236                                                int num_args, const type* types,
1237                                                int next_arg_id = 0)
1238       : base(fmt, next_arg_id), num_args_(num_args), types_(types) {}
1239 
1240   constexpr auto num_args() const -> int { return num_args_; }
1241   constexpr auto arg_type(int id) const -> type { return types_[id]; }
1242 
1243   FMT_CONSTEXPR auto next_arg_id() -> int {
1244     int id = base::next_arg_id();
1245     if (id >= num_args_) report_error("argument not found");
1246     return id;
1247   }
1248 
1249   FMT_CONSTEXPR void check_arg_id(int id) {
1250     base::check_arg_id(id);
1251     if (id >= num_args_) report_error("argument not found");
1252   }
1253   using base::check_arg_id;
1254 
1255   FMT_CONSTEXPR void check_dynamic_spec(int arg_id) {
1256     ignore_unused(arg_id);
1257     if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
1258       report_error("width/precision is not integer");
1259   }
1260 };
1261 
1262 // An argument reference.
1263 template <typename Char> union arg_ref {
1264   FMT_CONSTEXPR arg_ref(int idx = 0) : index(idx) {}
1265   FMT_CONSTEXPR arg_ref(basic_string_view<Char> n) : name(n) {}
1266 
1267   int index;
1268   basic_string_view<Char> name;
1269 };
1270 
1271 // Format specifiers with width and precision resolved at formatting rather
1272 // than parsing time to allow reusing the same parsed specifiers with
1273 // different sets of arguments (precompilation of format strings).
1274 template <typename Char = char> struct dynamic_format_specs : format_specs {
1275   arg_ref<Char> width_ref;
1276   arg_ref<Char> precision_ref;
1277 };
1278 
1279 // Converts a character to ASCII. Returns '\0' on conversion failure.
1280 template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
1281 constexpr auto to_ascii(Char c) -> char {
1282   return c <= 0xff ? static_cast<char>(c) : '\0';
1283 }
1284 
1285 // Returns the number of code units in a code point or 1 on error.
1286 template <typename Char>
1287 FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int {
1288   if (const_check(sizeof(Char) != 1)) return 1;
1289   auto c = static_cast<unsigned char>(*begin);
1290   return static_cast<int>((0x3a55000000000000ull >> (2 * (c >> 3))) & 3) + 1;
1291 }
1292 
1293 // Parses the range [begin, end) as an unsigned integer. This function assumes
1294 // that the range is non-empty and the first character is a digit.
1295 template <typename Char>
1296 FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end,
1297                                          int error_value) noexcept -> int {
1298   FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', "");
1299   unsigned value = 0, prev = 0;
1300   auto p = begin;
1301   do {
1302     prev = value;
1303     value = value * 10 + unsigned(*p - '0');
1304     ++p;
1305   } while (p != end && '0' <= *p && *p <= '9');
1306   auto num_digits = p - begin;
1307   begin = p;
1308   int digits10 = static_cast<int>(sizeof(int) * CHAR_BIT * 3 / 10);
1309   if (num_digits <= digits10) return static_cast<int>(value);
1310   // Check for overflow.
1311   unsigned max = INT_MAX;
1312   return num_digits == digits10 + 1 &&
1313                  prev * 10ull + unsigned(p[-1] - '0') <= max
1314              ? static_cast<int>(value)
1315              : error_value;
1316 }
1317 
1318 FMT_CONSTEXPR inline auto parse_align(char c) -> align {
1319   switch (c) {
1320   case '<': return align::left;
1321   case '>': return align::right;
1322   case '^': return align::center;
1323   }
1324   return align::none;
1325 }
1326 
1327 template <typename Char> constexpr auto is_name_start(Char c) -> bool {
1328   return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_';
1329 }
1330 
1331 template <typename Char, typename Handler>
1332 FMT_CONSTEXPR auto parse_arg_id(const Char* begin, const Char* end,
1333                                 Handler&& handler) -> const Char* {
1334   Char c = *begin;
1335   if (c >= '0' && c <= '9') {
1336     int index = 0;
1337     if (c != '0')
1338       index = parse_nonnegative_int(begin, end, INT_MAX);
1339     else
1340       ++begin;
1341     if (begin == end || (*begin != '}' && *begin != ':'))
1342       report_error("invalid format string");
1343     else
1344       handler.on_index(index);
1345     return begin;
1346   }
1347   if (FMT_OPTIMIZE_SIZE > 1 || !is_name_start(c)) {
1348     report_error("invalid format string");
1349     return begin;
1350   }
1351   auto it = begin;
1352   do {
1353     ++it;
1354   } while (it != end && (is_name_start(*it) || ('0' <= *it && *it <= '9')));
1355   handler.on_name({begin, to_unsigned(it - begin)});
1356   return it;
1357 }
1358 
1359 template <typename Char> struct dynamic_spec_handler {
1360   parse_context<Char>& ctx;
1361   arg_ref<Char>& ref;
1362   arg_id_kind& kind;
1363 
1364   FMT_CONSTEXPR void on_index(int id) {
1365     ref = id;
1366     kind = arg_id_kind::index;
1367     ctx.check_arg_id(id);
1368     ctx.check_dynamic_spec(id);
1369   }
1370   FMT_CONSTEXPR void on_name(basic_string_view<Char> id) {
1371     ref = id;
1372     kind = arg_id_kind::name;
1373     ctx.check_arg_id(id);
1374   }
1375 };
1376 
1377 template <typename Char> struct parse_dynamic_spec_result {
1378   const Char* end;
1379   arg_id_kind kind;
1380 };
1381 
1382 // Parses integer | "{" [arg_id] "}".
1383 template <typename Char>
1384 FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end,
1385                                       int& value, arg_ref<Char>& ref,
1386                                       parse_context<Char>& ctx)
1387     -> parse_dynamic_spec_result<Char> {
1388   FMT_ASSERT(begin != end, "");
1389   auto kind = arg_id_kind::none;
1390   if ('0' <= *begin && *begin <= '9') {
1391     int val = parse_nonnegative_int(begin, end, -1);
1392     if (val == -1) report_error("number is too big");
1393     value = val;
1394   } else {
1395     if (*begin == '{') {
1396       ++begin;
1397       if (begin != end) {
1398         Char c = *begin;
1399         if (c == '}' || c == ':') {
1400           int id = ctx.next_arg_id();
1401           ref = id;
1402           kind = arg_id_kind::index;
1403           ctx.check_dynamic_spec(id);
1404         } else {
1405           begin = parse_arg_id(begin, end,
1406                                dynamic_spec_handler<Char>{ctx, ref, kind});
1407         }
1408       }
1409       if (begin != end && *begin == '}') return {++begin, kind};
1410     }
1411     report_error("invalid format string");
1412   }
1413   return {begin, kind};
1414 }
1415 
1416 template <typename Char>
1417 FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end,
1418                                format_specs& specs, arg_ref<Char>& width_ref,
1419                                parse_context<Char>& ctx) -> const Char* {
1420   auto result = parse_dynamic_spec(begin, end, specs.width, width_ref, ctx);
1421   specs.set_dynamic_width(result.kind);
1422   return result.end;
1423 }
1424 
1425 template <typename Char>
1426 FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
1427                                    format_specs& specs,
1428                                    arg_ref<Char>& precision_ref,
1429                                    parse_context<Char>& ctx) -> const Char* {
1430   ++begin;
1431   if (begin == end) {
1432     report_error("invalid precision");
1433     return begin;
1434   }
1435   auto result =
1436       parse_dynamic_spec(begin, end, specs.precision, precision_ref, ctx);
1437   specs.set_dynamic_precision(result.kind);
1438   return result.end;
1439 }
1440 
1441 enum class state { start, align, sign, hash, zero, width, precision, locale };
1442 
1443 // Parses standard format specifiers.
1444 template <typename Char>
1445 FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
1446                                       dynamic_format_specs<Char>& specs,
1447                                       parse_context<Char>& ctx, type arg_type)
1448     -> const Char* {
1449   auto c = '\0';
1450   if (end - begin > 1) {
1451     auto next = to_ascii(begin[1]);
1452     c = parse_align(next) == align::none ? to_ascii(*begin) : '\0';
1453   } else {
1454     if (begin == end) return begin;
1455     c = to_ascii(*begin);
1456   }
1457 
1458   struct {
1459     state current_state = state::start;
1460     FMT_CONSTEXPR void operator()(state s, bool valid = true) {
1461       if (current_state >= s || !valid)
1462         report_error("invalid format specifier");
1463       current_state = s;
1464     }
1465   } enter_state;
1466 
1467   using pres = presentation_type;
1468   constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
1469   struct {
1470     const Char*& begin;
1471     format_specs& specs;
1472     type arg_type;
1473 
1474     FMT_CONSTEXPR auto operator()(pres pres_type, int set) -> const Char* {
1475       if (!in(arg_type, set)) report_error("invalid format specifier");
1476       specs.set_type(pres_type);
1477       return begin + 1;
1478     }
1479   } parse_presentation_type{begin, specs, arg_type};
1480 
1481   for (;;) {
1482     switch (c) {
1483     case '<':
1484     case '>':
1485     case '^':
1486       enter_state(state::align);
1487       specs.set_align(parse_align(c));
1488       ++begin;
1489       break;
1490     case '+':
1491     case ' ':
1492       specs.set_sign(c == ' ' ? sign::space : sign::plus);
1493       FMT_FALLTHROUGH;
1494     case '-':
1495       enter_state(state::sign, in(arg_type, sint_set | float_set));
1496       ++begin;
1497       break;
1498     case '#':
1499       enter_state(state::hash, is_arithmetic_type(arg_type));
1500       specs.set_alt();
1501       ++begin;
1502       break;
1503     case '0':
1504       enter_state(state::zero);
1505       if (!is_arithmetic_type(arg_type))
1506         report_error("format specifier requires numeric argument");
1507       if (specs.align() == align::none) {
1508         // Ignore 0 if align is specified for compatibility with std::format.
1509         specs.set_align(align::numeric);
1510         specs.set_fill('0');
1511       }
1512       ++begin;
1513       break;
1514       // clang-format off
1515     case '1': case '2': case '3': case '4': case '5':
1516     case '6': case '7': case '8': case '9': case '{':
1517       // clang-format on
1518       enter_state(state::width);
1519       begin = parse_width(begin, end, specs, specs.width_ref, ctx);
1520       break;
1521     case '.':
1522       enter_state(state::precision,
1523                   in(arg_type, float_set | string_set | cstring_set));
1524       begin = parse_precision(begin, end, specs, specs.precision_ref, ctx);
1525       break;
1526     case 'L':
1527       enter_state(state::locale, is_arithmetic_type(arg_type));
1528       specs.set_localized();
1529       ++begin;
1530       break;
1531     case 'd': return parse_presentation_type(pres::dec, integral_set);
1532     case 'X': specs.set_upper(); FMT_FALLTHROUGH;
1533     case 'x': return parse_presentation_type(pres::hex, integral_set);
1534     case 'o': return parse_presentation_type(pres::oct, integral_set);
1535     case 'B': specs.set_upper(); FMT_FALLTHROUGH;
1536     case 'b': return parse_presentation_type(pres::bin, integral_set);
1537     case 'E': specs.set_upper(); FMT_FALLTHROUGH;
1538     case 'e': return parse_presentation_type(pres::exp, float_set);
1539     case 'F': specs.set_upper(); FMT_FALLTHROUGH;
1540     case 'f': return parse_presentation_type(pres::fixed, float_set);
1541     case 'G': specs.set_upper(); FMT_FALLTHROUGH;
1542     case 'g': return parse_presentation_type(pres::general, float_set);
1543     case 'A': specs.set_upper(); FMT_FALLTHROUGH;
1544     case 'a': return parse_presentation_type(pres::hexfloat, float_set);
1545     case 'c':
1546       if (arg_type == type::bool_type) report_error("invalid format specifier");
1547       return parse_presentation_type(pres::chr, integral_set);
1548     case 's':
1549       return parse_presentation_type(pres::string,
1550                                      bool_set | string_set | cstring_set);
1551     case 'p':
1552       return parse_presentation_type(pres::pointer, pointer_set | cstring_set);
1553     case '?':
1554       return parse_presentation_type(pres::debug,
1555                                      char_set | string_set | cstring_set);
1556     case '}': return begin;
1557     default:  {
1558       if (*begin == '}') return begin;
1559       // Parse fill and alignment.
1560       auto fill_end = begin + code_point_length(begin);
1561       if (end - fill_end <= 0) {
1562         report_error("invalid format specifier");
1563         return begin;
1564       }
1565       if (*begin == '{') {
1566         report_error("invalid fill character '{'");
1567         return begin;
1568       }
1569       auto alignment = parse_align(to_ascii(*fill_end));
1570       enter_state(state::align, alignment != align::none);
1571       specs.set_fill(
1572           basic_string_view<Char>(begin, to_unsigned(fill_end - begin)));
1573       specs.set_align(alignment);
1574       begin = fill_end + 1;
1575     }
1576     }
1577     if (begin == end) return begin;
1578     c = to_ascii(*begin);
1579   }
1580 }
1581 
1582 template <typename Char, typename Handler>
1583 FMT_CONSTEXPR FMT_INLINE auto parse_replacement_field(const Char* begin,
1584                                                       const Char* end,
1585                                                       Handler&& handler)
1586     -> const Char* {
1587   ++begin;
1588   if (begin == end) {
1589     handler.on_error("invalid format string");
1590     return end;
1591   }
1592   int arg_id = 0;
1593   switch (*begin) {
1594   case '}':
1595     handler.on_replacement_field(handler.on_arg_id(), begin);
1596     return begin + 1;
1597   case '{': handler.on_text(begin, begin + 1); return begin + 1;
1598   case ':': arg_id = handler.on_arg_id(); break;
1599   default:  {
1600     struct id_adapter {
1601       Handler& handler;
1602       int arg_id;
1603 
1604       FMT_CONSTEXPR void on_index(int id) { arg_id = handler.on_arg_id(id); }
1605       FMT_CONSTEXPR void on_name(basic_string_view<Char> id) {
1606         arg_id = handler.on_arg_id(id);
1607       }
1608     } adapter = {handler, 0};
1609     begin = parse_arg_id(begin, end, adapter);
1610     arg_id = adapter.arg_id;
1611     Char c = begin != end ? *begin : Char();
1612     if (c == '}') {
1613       handler.on_replacement_field(arg_id, begin);
1614       return begin + 1;
1615     }
1616     if (c != ':') {
1617       handler.on_error("missing '}' in format string");
1618       return end;
1619     }
1620     break;
1621   }
1622   }
1623   begin = handler.on_format_specs(arg_id, begin + 1, end);
1624   if (begin == end || *begin != '}')
1625     return handler.on_error("unknown format specifier"), end;
1626   return begin + 1;
1627 }
1628 
1629 template <typename Char, typename Handler>
1630 FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> fmt,
1631                                        Handler&& handler) {
1632   auto begin = fmt.data(), end = begin + fmt.size();
1633   auto p = begin;
1634   while (p != end) {
1635     auto c = *p++;
1636     if (c == '{') {
1637       handler.on_text(begin, p - 1);
1638       begin = p = parse_replacement_field(p - 1, end, handler);
1639     } else if (c == '}') {
1640       if (p == end || *p != '}')
1641         return handler.on_error("unmatched '}' in format string");
1642       handler.on_text(begin, p);
1643       begin = ++p;
1644     }
1645   }
1646   handler.on_text(begin, end);
1647 }
1648 
1649 // Checks char specs and returns true iff the presentation type is char-like.
1650 FMT_CONSTEXPR inline auto check_char_specs(const format_specs& specs) -> bool {
1651   auto type = specs.type();
1652   if (type != presentation_type::none && type != presentation_type::chr &&
1653       type != presentation_type::debug) {
1654     return false;
1655   }
1656   if (specs.align() == align::numeric || specs.sign() != sign::none ||
1657       specs.alt()) {
1658     report_error("invalid format specifier for char");
1659   }
1660   return true;
1661 }
1662 
1663 // A base class for compile-time strings.
1664 struct compile_string {};
1665 
1666 template <typename T, typename Char>
1667 FMT_VISIBILITY("hidden")  // Suppress an ld warning on macOS (#3769).
1668 FMT_CONSTEXPR auto invoke_parse(parse_context<Char>& ctx) -> const Char* {
1669   using mapped_type = remove_cvref_t<mapped_t<T, Char>>;
1670   constexpr bool formattable =
1671       std::is_constructible<formatter<mapped_type, Char>>::value;
1672   if (!formattable) return ctx.begin();  // Error is reported in the value ctor.
1673   using formatted_type = conditional_t<formattable, mapped_type, int>;
1674   return formatter<formatted_type, Char>().parse(ctx);
1675 }
1676 
1677 template <typename... T> struct arg_pack {};
1678 
1679 template <typename Char, int NUM_ARGS, int NUM_NAMED_ARGS, bool DYNAMIC_NAMES>
1680 class format_string_checker {
1681  private:
1682   type types_[max_of(1, NUM_ARGS)];
1683   named_arg_info<Char> named_args_[max_of(1, NUM_NAMED_ARGS)];
1684   compile_parse_context<Char> context_;
1685 
1686   using parse_func = auto (*)(parse_context<Char>&) -> const Char*;
1687   parse_func parse_funcs_[max_of(1, NUM_ARGS)];
1688 
1689  public:
1690   template <typename... T>
1691   FMT_CONSTEXPR explicit format_string_checker(basic_string_view<Char> fmt,
1692                                                arg_pack<T...>)
1693       : types_{mapped_type_constant<T, Char>::value...},
1694         named_args_{},
1695         context_(fmt, NUM_ARGS, types_),
1696         parse_funcs_{&invoke_parse<T, Char>...} {
1697     int arg_index = 0, named_arg_index = 0;
1698     FMT_APPLY_VARIADIC(
1699         init_static_named_arg<T>(named_args_, arg_index, named_arg_index));
1700     ignore_unused(arg_index, named_arg_index);
1701   }
1702 
1703   FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
1704 
1705   FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); }
1706   FMT_CONSTEXPR auto on_arg_id(int id) -> int {
1707     context_.check_arg_id(id);
1708     return id;
1709   }
1710   FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
1711     for (int i = 0; i < NUM_NAMED_ARGS; ++i) {
1712       if (named_args_[i].name == id) return named_args_[i].id;
1713     }
1714     if (!DYNAMIC_NAMES) on_error("argument not found");
1715     return -1;
1716   }
1717 
1718   FMT_CONSTEXPR void on_replacement_field(int id, const Char* begin) {
1719     on_format_specs(id, begin, begin);  // Call parse() on empty specs.
1720   }
1721 
1722   FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char* end)
1723       -> const Char* {
1724     context_.advance_to(begin);
1725     if (id >= 0 && id < NUM_ARGS) return parse_funcs_[id](context_);
1726 
1727     // If id is out of range, it means we do not know the type and cannot parse
1728     // the format at compile time. Instead, skip over content until we finish
1729     // the format spec, accounting for any nested replacements.
1730     for (int bracket_count = 0;
1731          begin != end && (bracket_count > 0 || *begin != '}'); ++begin) {
1732       if (*begin == '{')
1733         ++bracket_count;
1734       else if (*begin == '}')
1735         --bracket_count;
1736     }
1737     return begin;
1738   }
1739 
1740   FMT_NORETURN FMT_CONSTEXPR void on_error(const char* message) {
1741     report_error(message);
1742   }
1743 };
1744 
1745 /// A contiguous memory buffer with an optional growing ability. It is an
1746 /// internal class and shouldn't be used directly, only via `memory_buffer`.
1747 template <typename T> class buffer {
1748  private:
1749   T* ptr_;
1750   size_t size_;
1751   size_t capacity_;
1752 
1753   using grow_fun = void (*)(buffer& buf, size_t capacity);
1754   grow_fun grow_;
1755 
1756  protected:
1757   // Don't initialize ptr_ since it is not accessed to save a few cycles.
1758   FMT_MSC_WARNING(suppress : 26495)
1759   FMT_CONSTEXPR buffer(grow_fun grow, size_t sz) noexcept
1760       : size_(sz), capacity_(sz), grow_(grow) {}
1761 
1762   constexpr buffer(grow_fun grow, T* p = nullptr, size_t sz = 0,
1763                    size_t cap = 0) noexcept
1764       : ptr_(p), size_(sz), capacity_(cap), grow_(grow) {}
1765 
1766   FMT_CONSTEXPR20 ~buffer() = default;
1767   buffer(buffer&&) = default;
1768 
1769   /// Sets the buffer data and capacity.
1770   FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) noexcept {
1771     ptr_ = buf_data;
1772     capacity_ = buf_capacity;
1773   }
1774 
1775  public:
1776   using value_type = T;
1777   using const_reference = const T&;
1778 
1779   buffer(const buffer&) = delete;
1780   void operator=(const buffer&) = delete;
1781 
1782   auto begin() noexcept -> T* { return ptr_; }
1783   auto end() noexcept -> T* { return ptr_ + size_; }
1784 
1785   auto begin() const noexcept -> const T* { return ptr_; }
1786   auto end() const noexcept -> const T* { return ptr_ + size_; }
1787 
1788   /// Returns the size of this buffer.
1789   constexpr auto size() const noexcept -> size_t { return size_; }
1790 
1791   /// Returns the capacity of this buffer.
1792   constexpr auto capacity() const noexcept -> size_t { return capacity_; }
1793 
1794   /// Returns a pointer to the buffer data (not null-terminated).
1795   FMT_CONSTEXPR auto data() noexcept -> T* { return ptr_; }
1796   FMT_CONSTEXPR auto data() const noexcept -> const T* { return ptr_; }
1797 
1798   /// Clears this buffer.
1799   FMT_CONSTEXPR void clear() { size_ = 0; }
1800 
1801   // Tries resizing the buffer to contain `count` elements. If T is a POD type
1802   // the new elements may not be initialized.
1803   FMT_CONSTEXPR void try_resize(size_t count) {
1804     try_reserve(count);
1805     size_ = min_of(count, capacity_);
1806   }
1807 
1808   // Tries increasing the buffer capacity to `new_capacity`. It can increase the
1809   // capacity by a smaller amount than requested but guarantees there is space
1810   // for at least one additional element either by increasing the capacity or by
1811   // flushing the buffer if it is full.
1812   FMT_CONSTEXPR void try_reserve(size_t new_capacity) {
1813     if (new_capacity > capacity_) grow_(*this, new_capacity);
1814   }
1815 
1816   FMT_CONSTEXPR void push_back(const T& value) {
1817     try_reserve(size_ + 1);
1818     ptr_[size_++] = value;
1819   }
1820 
1821   /// Appends data to the end of the buffer.
1822   template <typename U>
1823 // Workaround for MSVC2019 to fix error C2893: Failed to specialize function
1824 // template 'void fmt::v11::detail::buffer<T>::append(const U *,const U *)'.
1825 #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1940
1826   FMT_CONSTEXPR20
1827 #endif
1828       void
1829       append(const U* begin, const U* end) {
1830     while (begin != end) {
1831       auto count = to_unsigned(end - begin);
1832       try_reserve(size_ + count);
1833       auto free_cap = capacity_ - size_;
1834       if (free_cap < count) count = free_cap;
1835       // A loop is faster than memcpy on small sizes.
1836       T* out = ptr_ + size_;
1837       for (size_t i = 0; i < count; ++i) out[i] = begin[i];
1838       size_ += count;
1839       begin += count;
1840     }
1841   }
1842 
1843   template <typename Idx> FMT_CONSTEXPR auto operator[](Idx index) -> T& {
1844     return ptr_[index];
1845   }
1846   template <typename Idx>
1847   FMT_CONSTEXPR auto operator[](Idx index) const -> const T& {
1848     return ptr_[index];
1849   }
1850 };
1851 
1852 struct buffer_traits {
1853   constexpr explicit buffer_traits(size_t) {}
1854   constexpr auto count() const -> size_t { return 0; }
1855   constexpr auto limit(size_t size) const -> size_t { return size; }
1856 };
1857 
1858 class fixed_buffer_traits {
1859  private:
1860   size_t count_ = 0;
1861   size_t limit_;
1862 
1863  public:
1864   constexpr explicit fixed_buffer_traits(size_t limit) : limit_(limit) {}
1865   constexpr auto count() const -> size_t { return count_; }
1866   FMT_CONSTEXPR auto limit(size_t size) -> size_t {
1867     size_t n = limit_ > count_ ? limit_ - count_ : 0;
1868     count_ += size;
1869     return min_of(size, n);
1870   }
1871 };
1872 
1873 // A buffer that writes to an output iterator when flushed.
1874 template <typename OutputIt, typename T, typename Traits = buffer_traits>
1875 class iterator_buffer : public Traits, public buffer<T> {
1876  private:
1877   OutputIt out_;
1878   enum { buffer_size = 256 };
1879   T data_[buffer_size];
1880 
1881   static FMT_CONSTEXPR void grow(buffer<T>& buf, size_t) {
1882     if (buf.size() == buffer_size) static_cast<iterator_buffer&>(buf).flush();
1883   }
1884 
1885   void flush() {
1886     auto size = this->size();
1887     this->clear();
1888     const T* begin = data_;
1889     const T* end = begin + this->limit(size);
1890     while (begin != end) *out_++ = *begin++;
1891   }
1892 
1893  public:
1894   explicit iterator_buffer(OutputIt out, size_t n = buffer_size)
1895       : Traits(n), buffer<T>(grow, data_, 0, buffer_size), out_(out) {}
1896   iterator_buffer(iterator_buffer&& other) noexcept
1897       : Traits(other),
1898         buffer<T>(grow, data_, 0, buffer_size),
1899         out_(other.out_) {}
1900   ~iterator_buffer() {
1901     // Don't crash if flush fails during unwinding.
1902     FMT_TRY { flush(); }
1903     FMT_CATCH(...) {}
1904   }
1905 
1906   auto out() -> OutputIt {
1907     flush();
1908     return out_;
1909   }
1910   auto count() const -> size_t { return Traits::count() + this->size(); }
1911 };
1912 
1913 template <typename T>
1914 class iterator_buffer<T*, T, fixed_buffer_traits> : public fixed_buffer_traits,
1915                                                     public buffer<T> {
1916  private:
1917   T* out_;
1918   enum { buffer_size = 256 };
1919   T data_[buffer_size];
1920 
1921   static FMT_CONSTEXPR void grow(buffer<T>& buf, size_t) {
1922     if (buf.size() == buf.capacity())
1923       static_cast<iterator_buffer&>(buf).flush();
1924   }
1925 
1926   void flush() {
1927     size_t n = this->limit(this->size());
1928     if (this->data() == out_) {
1929       out_ += n;
1930       this->set(data_, buffer_size);
1931     }
1932     this->clear();
1933   }
1934 
1935  public:
1936   explicit iterator_buffer(T* out, size_t n = buffer_size)
1937       : fixed_buffer_traits(n), buffer<T>(grow, out, 0, n), out_(out) {}
1938   iterator_buffer(iterator_buffer&& other) noexcept
1939       : fixed_buffer_traits(other),
1940         buffer<T>(static_cast<iterator_buffer&&>(other)),
1941         out_(other.out_) {
1942     if (this->data() != out_) {
1943       this->set(data_, buffer_size);
1944       this->clear();
1945     }
1946   }
1947   ~iterator_buffer() { flush(); }
1948 
1949   auto out() -> T* {
1950     flush();
1951     return out_;
1952   }
1953   auto count() const -> size_t {
1954     return fixed_buffer_traits::count() + this->size();
1955   }
1956 };
1957 
1958 template <typename T> class iterator_buffer<T*, T> : public buffer<T> {
1959  public:
1960   explicit iterator_buffer(T* out, size_t = 0)
1961       : buffer<T>([](buffer<T>&, size_t) {}, out, 0, ~size_t()) {}
1962 
1963   auto out() -> T* { return &*this->end(); }
1964 };
1965 
1966 template <typename Container>
1967 class container_buffer : public buffer<typename Container::value_type> {
1968  private:
1969   using value_type = typename Container::value_type;
1970 
1971   static FMT_CONSTEXPR void grow(buffer<value_type>& buf, size_t capacity) {
1972     auto& self = static_cast<container_buffer&>(buf);
1973     self.container.resize(capacity);
1974     self.set(&self.container[0], capacity);
1975   }
1976 
1977  public:
1978   Container& container;
1979 
1980   explicit container_buffer(Container& c)
1981       : buffer<value_type>(grow, c.size()), container(c) {}
1982 };
1983 
1984 // A buffer that writes to a container with the contiguous storage.
1985 template <typename OutputIt>
1986 class iterator_buffer<
1987     OutputIt,
1988     enable_if_t<is_back_insert_iterator<OutputIt>::value &&
1989                     is_contiguous<typename OutputIt::container_type>::value,
1990                 typename OutputIt::container_type::value_type>>
1991     : public container_buffer<typename OutputIt::container_type> {
1992  private:
1993   using base = container_buffer<typename OutputIt::container_type>;
1994 
1995  public:
1996   explicit iterator_buffer(typename OutputIt::container_type& c) : base(c) {}
1997   explicit iterator_buffer(OutputIt out, size_t = 0)
1998       : base(get_container(out)) {}
1999 
2000   auto out() -> OutputIt { return OutputIt(this->container); }
2001 };
2002 
2003 // A buffer that counts the number of code units written discarding the output.
2004 template <typename T = char> class counting_buffer : public buffer<T> {
2005  private:
2006   enum { buffer_size = 256 };
2007   T data_[buffer_size];
2008   size_t count_ = 0;
2009 
2010   static FMT_CONSTEXPR void grow(buffer<T>& buf, size_t) {
2011     if (buf.size() != buffer_size) return;
2012     static_cast<counting_buffer&>(buf).count_ += buf.size();
2013     buf.clear();
2014   }
2015 
2016  public:
2017   FMT_CONSTEXPR counting_buffer() : buffer<T>(grow, data_, 0, buffer_size) {}
2018 
2019   constexpr auto count() const noexcept -> size_t {
2020     return count_ + this->size();
2021   }
2022 };
2023 
2024 template <typename T>
2025 struct is_back_insert_iterator<basic_appender<T>> : std::true_type {};
2026 
2027 template <typename OutputIt, typename InputIt, typename = void>
2028 struct has_back_insert_iterator_container_append : std::false_type {};
2029 template <typename OutputIt, typename InputIt>
2030 struct has_back_insert_iterator_container_append<
2031     OutputIt, InputIt,
2032     void_t<decltype(get_container(std::declval<OutputIt>())
2033                         .append(std::declval<InputIt>(),
2034                                 std::declval<InputIt>()))>> : std::true_type {};
2035 
2036 // An optimized version of std::copy with the output value type (T).
2037 template <typename T, typename InputIt, typename OutputIt,
2038           FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value&&
2039                             has_back_insert_iterator_container_append<
2040                                 OutputIt, InputIt>::value)>
2041 FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out)
2042     -> OutputIt {
2043   get_container(out).append(begin, end);
2044   return out;
2045 }
2046 
2047 template <typename T, typename InputIt, typename OutputIt,
2048           FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value &&
2049                         !has_back_insert_iterator_container_append<
2050                             OutputIt, InputIt>::value)>
2051 FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out)
2052     -> OutputIt {
2053   auto& c = get_container(out);
2054   c.insert(c.end(), begin, end);
2055   return out;
2056 }
2057 
2058 template <typename T, typename InputIt, typename OutputIt,
2059           FMT_ENABLE_IF(!is_back_insert_iterator<OutputIt>::value)>
2060 FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
2061   while (begin != end) *out++ = static_cast<T>(*begin++);
2062   return out;
2063 }
2064 
2065 template <typename T, typename V, typename OutputIt>
2066 FMT_CONSTEXPR auto copy(basic_string_view<V> s, OutputIt out) -> OutputIt {
2067   return copy<T>(s.begin(), s.end(), out);
2068 }
2069 
2070 template <typename It, typename Enable = std::true_type>
2071 struct is_buffer_appender : std::false_type {};
2072 template <typename It>
2073 struct is_buffer_appender<
2074     It, bool_constant<
2075             is_back_insert_iterator<It>::value &&
2076             std::is_base_of<buffer<typename It::container_type::value_type>,
2077                             typename It::container_type>::value>>
2078     : std::true_type {};
2079 
2080 // Maps an output iterator to a buffer.
2081 template <typename T, typename OutputIt,
2082           FMT_ENABLE_IF(!is_buffer_appender<OutputIt>::value)>
2083 auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> {
2084   return iterator_buffer<OutputIt, T>(out);
2085 }
2086 template <typename T, typename OutputIt,
2087           FMT_ENABLE_IF(is_buffer_appender<OutputIt>::value)>
2088 auto get_buffer(OutputIt out) -> buffer<T>& {
2089   return get_container(out);
2090 }
2091 
2092 template <typename Buf, typename OutputIt>
2093 auto get_iterator(Buf& buf, OutputIt) -> decltype(buf.out()) {
2094   return buf.out();
2095 }
2096 template <typename T, typename OutputIt>
2097 auto get_iterator(buffer<T>&, OutputIt out) -> OutputIt {
2098   return out;
2099 }
2100 
2101 // This type is intentionally undefined, only used for errors.
2102 template <typename T, typename Char> struct type_is_unformattable_for;
2103 
2104 template <typename Char> struct string_value {
2105   const Char* data;
2106   size_t size;
2107   auto str() const -> basic_string_view<Char> { return {data, size}; }
2108 };
2109 
2110 template <typename Context> struct custom_value {
2111   using char_type = typename Context::char_type;
2112   void* value;
2113   void (*format)(void* arg, parse_context<char_type>& parse_ctx, Context& ctx);
2114 };
2115 
2116 template <typename Char> struct named_arg_value {
2117   const named_arg_info<Char>* data;
2118   size_t size;
2119 };
2120 
2121 struct custom_tag {};
2122 
2123 #if !FMT_BUILTIN_TYPES
2124 #  define FMT_BUILTIN , monostate
2125 #else
2126 #  define FMT_BUILTIN
2127 #endif
2128 
2129 // A formatting argument value.
2130 template <typename Context> class value {
2131  public:
2132   using char_type = typename Context::char_type;
2133 
2134   union {
2135     monostate no_value;
2136     int int_value;
2137     unsigned uint_value;
2138     long long long_long_value;
2139     unsigned long long ulong_long_value;
2140     int128_opt int128_value;
2141     uint128_opt uint128_value;
2142     bool bool_value;
2143     char_type char_value;
2144     float float_value;
2145     double double_value;
2146     long double long_double_value;
2147     const void* pointer;
2148     string_value<char_type> string;
2149     custom_value<Context> custom;
2150     named_arg_value<char_type> named_args;
2151   };
2152 
2153   constexpr FMT_INLINE value() : no_value() {}
2154   constexpr FMT_INLINE value(signed char x) : int_value(x) {}
2155   constexpr FMT_INLINE value(unsigned char x FMT_BUILTIN) : uint_value(x) {}
2156   constexpr FMT_INLINE value(signed short x) : int_value(x) {}
2157   constexpr FMT_INLINE value(unsigned short x FMT_BUILTIN) : uint_value(x) {}
2158   constexpr FMT_INLINE value(int x) : int_value(x) {}
2159   constexpr FMT_INLINE value(unsigned x FMT_BUILTIN) : uint_value(x) {}
2160   FMT_CONSTEXPR FMT_INLINE value(long x FMT_BUILTIN) : value(long_type(x)) {}
2161   FMT_CONSTEXPR FMT_INLINE value(unsigned long x FMT_BUILTIN)
2162       : value(ulong_type(x)) {}
2163   constexpr FMT_INLINE value(long long x FMT_BUILTIN) : long_long_value(x) {}
2164   constexpr FMT_INLINE value(unsigned long long x FMT_BUILTIN)
2165       : ulong_long_value(x) {}
2166   FMT_INLINE value(int128_opt x FMT_BUILTIN) : int128_value(x) {}
2167   FMT_INLINE value(uint128_opt x FMT_BUILTIN) : uint128_value(x) {}
2168   constexpr FMT_INLINE value(bool x FMT_BUILTIN) : bool_value(x) {}
2169 
2170   template <int N>
2171   constexpr FMT_INLINE value(bitint<N> x FMT_BUILTIN) : long_long_value(x) {
2172     static_assert(N <= 64, "unsupported _BitInt");
2173   }
2174   template <int N>
2175   constexpr FMT_INLINE value(ubitint<N> x FMT_BUILTIN) : ulong_long_value(x) {
2176     static_assert(N <= 64, "unsupported _BitInt");
2177   }
2178 
2179   template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
2180   constexpr FMT_INLINE value(T x FMT_BUILTIN) : char_value(x) {
2181     static_assert(
2182         std::is_same<T, char>::value || std::is_same<T, char_type>::value,
2183         "mixing character types is disallowed");
2184   }
2185 
2186   constexpr FMT_INLINE value(float x FMT_BUILTIN) : float_value(x) {}
2187   constexpr FMT_INLINE value(double x FMT_BUILTIN) : double_value(x) {}
2188   FMT_INLINE value(long double x FMT_BUILTIN) : long_double_value(x) {}
2189 
2190   FMT_CONSTEXPR FMT_INLINE value(char_type* x FMT_BUILTIN) {
2191     string.data = x;
2192     if (is_constant_evaluated()) string.size = 0;
2193   }
2194   FMT_CONSTEXPR FMT_INLINE value(const char_type* x FMT_BUILTIN) {
2195     string.data = x;
2196     if (is_constant_evaluated()) string.size = 0;
2197   }
2198   template <typename T, typename C = char_t<T>,
2199             FMT_ENABLE_IF(!std::is_pointer<T>::value)>
2200   FMT_CONSTEXPR value(const T& x FMT_BUILTIN) {
2201     static_assert(std::is_same<C, char_type>::value,
2202                   "mixing character types is disallowed");
2203     auto sv = to_string_view(x);
2204     string.data = sv.data();
2205     string.size = sv.size();
2206   }
2207   FMT_INLINE value(void* x FMT_BUILTIN) : pointer(x) {}
2208   FMT_INLINE value(const void* x FMT_BUILTIN) : pointer(x) {}
2209   FMT_INLINE value(volatile void* x FMT_BUILTIN)
2210       : pointer(const_cast<const void*>(x)) {}
2211   FMT_INLINE value(const volatile void* x FMT_BUILTIN)
2212       : pointer(const_cast<const void*>(x)) {}
2213   FMT_INLINE value(nullptr_t) : pointer(nullptr) {}
2214 
2215   template <typename T, FMT_ENABLE_IF(std::is_pointer<T>::value ||
2216                                       std::is_member_pointer<T>::value)>
2217   value(const T&) {
2218     // Formatting of arbitrary pointers is disallowed. If you want to format a
2219     // pointer cast it to `void*` or `const void*`. In particular, this forbids
2220     // formatting of `[const] volatile char*` printed as bool by iostreams.
2221     static_assert(sizeof(T) == 0,
2222                   "formatting of non-void pointers is disallowed");
2223   }
2224 
2225   template <typename T, FMT_ENABLE_IF(use_format_as<T>::value)>
2226   value(const T& x) : value(format_as(x)) {}
2227   template <typename T, FMT_ENABLE_IF(use_format_as_member<T>::value)>
2228   value(const T& x) : value(formatter<T>::format_as(x)) {}
2229 
2230   template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
2231   value(const T& named_arg) : value(named_arg.value) {}
2232 
2233   template <typename T,
2234             FMT_ENABLE_IF(use_formatter<T>::value || !FMT_BUILTIN_TYPES)>
2235   FMT_CONSTEXPR20 FMT_INLINE value(T& x) : value(x, custom_tag()) {}
2236 
2237   FMT_ALWAYS_INLINE value(const named_arg_info<char_type>* args, size_t size)
2238       : named_args{args, size} {}
2239 
2240  private:
2241   template <typename T, FMT_ENABLE_IF(has_formatter<T, char_type>())>
2242   FMT_CONSTEXPR value(T& x, custom_tag) {
2243     using value_type = remove_const_t<T>;
2244     // T may overload operator& e.g. std::vector<bool>::reference in libc++.
2245     if (!is_constant_evaluated()) {
2246       custom.value =
2247           const_cast<char*>(&reinterpret_cast<const volatile char&>(x));
2248     } else {
2249       custom.value = nullptr;
2250 #if defined(__cpp_if_constexpr)
2251       if constexpr (std::is_same<decltype(&x), remove_reference_t<T>*>::value)
2252         custom.value = const_cast<value_type*>(&x);
2253 #endif
2254     }
2255     custom.format = format_custom<value_type, formatter<value_type, char_type>>;
2256   }
2257 
2258   template <typename T, FMT_ENABLE_IF(!has_formatter<T, char_type>())>
2259   FMT_CONSTEXPR value(const T&, custom_tag) {
2260     // Cannot format an argument; to make type T formattable provide a
2261     // formatter<T> specialization: https://fmt.dev/latest/api.html#udt.
2262     type_is_unformattable_for<T, char_type> _;
2263   }
2264 
2265   // Formats an argument of a custom type, such as a user-defined class.
2266   template <typename T, typename Formatter>
2267   static void format_custom(void* arg, parse_context<char_type>& parse_ctx,
2268                             Context& ctx) {
2269     auto f = Formatter();
2270     parse_ctx.advance_to(f.parse(parse_ctx));
2271     using qualified_type =
2272         conditional_t<has_formatter<const T, char_type>(), const T, T>;
2273     // format must be const for compatibility with std::format and compilation.
2274     const auto& cf = f;
2275     ctx.advance_to(cf.format(*static_cast<qualified_type*>(arg), ctx));
2276   }
2277 };
2278 
2279 enum { packed_arg_bits = 4 };
2280 // Maximum number of arguments with packed types.
2281 enum { max_packed_args = 62 / packed_arg_bits };
2282 enum : unsigned long long { is_unpacked_bit = 1ULL << 63 };
2283 enum : unsigned long long { has_named_args_bit = 1ULL << 62 };
2284 
2285 template <typename It, typename T, typename Enable = void>
2286 struct is_output_iterator : std::false_type {};
2287 
2288 template <> struct is_output_iterator<appender, char> : std::true_type {};
2289 
2290 template <typename It, typename T>
2291 struct is_output_iterator<
2292     It, T,
2293     enable_if_t<std::is_assignable<decltype(*std::declval<decay_t<It>&>()++),
2294                                    T>::value>> : std::true_type {};
2295 
2296 #ifndef FMT_USE_LOCALE
2297 #  define FMT_USE_LOCALE (FMT_OPTIMIZE_SIZE <= 1)
2298 #endif
2299 
2300 // A type-erased reference to an std::locale to avoid a heavy <locale> include.
2301 class locale_ref {
2302 #if FMT_USE_LOCALE
2303  private:
2304   const void* locale_;  // A type-erased pointer to std::locale.
2305 
2306  public:
2307   constexpr locale_ref() : locale_(nullptr) {}
2308   template <typename Locale> locale_ref(const Locale& loc);
2309 
2310   inline explicit operator bool() const noexcept { return locale_ != nullptr; }
2311 #endif  // FMT_USE_LOCALE
2312 
2313  public:
2314   template <typename Locale> auto get() const -> Locale;
2315 };
2316 
2317 template <typename> constexpr auto encode_types() -> unsigned long long {
2318   return 0;
2319 }
2320 
2321 template <typename Context, typename Arg, typename... Args>
2322 constexpr auto encode_types() -> unsigned long long {
2323   return static_cast<unsigned>(stored_type_constant<Arg, Context>::value) |
2324          (encode_types<Context, Args...>() << packed_arg_bits);
2325 }
2326 
2327 template <typename Context, typename... T, size_t NUM_ARGS = sizeof...(T)>
2328 constexpr auto make_descriptor() -> unsigned long long {
2329   return NUM_ARGS <= max_packed_args ? encode_types<Context, T...>()
2330                                      : is_unpacked_bit | NUM_ARGS;
2331 }
2332 
2333 template <typename Context, int NUM_ARGS>
2334 using arg_t = conditional_t<NUM_ARGS <= max_packed_args, value<Context>,
2335                             basic_format_arg<Context>>;
2336 
2337 template <typename Context, int NUM_ARGS, int NUM_NAMED_ARGS,
2338           unsigned long long DESC>
2339 struct named_arg_store {
2340   // args_[0].named_args points to named_args to avoid bloating format_args.
2341   arg_t<Context, NUM_ARGS> args[1 + NUM_ARGS];
2342   named_arg_info<typename Context::char_type> named_args[NUM_NAMED_ARGS];
2343 
2344   template <typename... T>
2345   FMT_CONSTEXPR FMT_ALWAYS_INLINE named_arg_store(T&... values)
2346       : args{{named_args, NUM_NAMED_ARGS}, values...} {
2347     int arg_index = 0, named_arg_index = 0;
2348     FMT_APPLY_VARIADIC(
2349         init_named_arg(named_args, arg_index, named_arg_index, values));
2350   }
2351 
2352   named_arg_store(named_arg_store&& rhs) {
2353     args[0] = {named_args, NUM_NAMED_ARGS};
2354     for (size_t i = 1; i < sizeof(args) / sizeof(*args); ++i)
2355       args[i] = rhs.args[i];
2356     for (size_t i = 0; i < NUM_NAMED_ARGS; ++i)
2357       named_args[i] = rhs.named_args[i];
2358   }
2359 
2360   named_arg_store(const named_arg_store& rhs) = delete;
2361   named_arg_store& operator=(const named_arg_store& rhs) = delete;
2362   named_arg_store& operator=(named_arg_store&& rhs) = delete;
2363   operator const arg_t<Context, NUM_ARGS>*() const { return args + 1; }
2364 };
2365 
2366 // An array of references to arguments. It can be implicitly converted to
2367 // `basic_format_args` for passing into type-erased formatting functions
2368 // such as `vformat`. It is a plain struct to reduce binary size in debug mode.
2369 template <typename Context, int NUM_ARGS, int NUM_NAMED_ARGS,
2370           unsigned long long DESC>
2371 struct format_arg_store {
2372   // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
2373   using type =
2374       conditional_t<NUM_NAMED_ARGS == 0,
2375                     arg_t<Context, NUM_ARGS>[max_of(1, NUM_ARGS)],
2376                     named_arg_store<Context, NUM_ARGS, NUM_NAMED_ARGS, DESC>>;
2377   type args;
2378 };
2379 
2380 // TYPE can be different from type_constant<T>, e.g. for __float128.
2381 template <typename T, typename Char, type TYPE> struct native_formatter {
2382  private:
2383   dynamic_format_specs<Char> specs_;
2384 
2385  public:
2386   using nonlocking = void;
2387 
2388   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2389     if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin();
2390     auto end = parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, TYPE);
2391     if (const_check(TYPE == type::char_type)) check_char_specs(specs_);
2392     return end;
2393   }
2394 
2395   template <type U = TYPE,
2396             FMT_ENABLE_IF(U == type::string_type || U == type::cstring_type ||
2397                           U == type::char_type)>
2398   FMT_CONSTEXPR void set_debug_format(bool set = true) {
2399     specs_.set_type(set ? presentation_type::debug : presentation_type::none);
2400   }
2401 
2402   FMT_PRAGMA_CLANG(diagnostic ignored "-Wundefined-inline")
2403   template <typename FormatContext>
2404   FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const
2405       -> decltype(ctx.out());
2406 };
2407 
2408 template <typename T, typename Enable = void>
2409 struct locking
2410     : bool_constant<mapped_type_constant<T>::value == type::custom_type> {};
2411 template <typename T>
2412 struct locking<T, void_t<typename formatter<remove_cvref_t<T>>::nonlocking>>
2413     : std::false_type {};
2414 
2415 template <typename T = int> FMT_CONSTEXPR inline auto is_locking() -> bool {
2416   return locking<T>::value;
2417 }
2418 template <typename T1, typename T2, typename... Tail>
2419 FMT_CONSTEXPR inline auto is_locking() -> bool {
2420   return locking<T1>::value || is_locking<T2, Tail...>();
2421 }
2422 
2423 FMT_API void vformat_to(buffer<char>& buf, string_view fmt, format_args args,
2424                         locale_ref loc = {});
2425 
2426 #if FMT_WIN32
2427 FMT_API void vprint_mojibake(FILE*, string_view, format_args, bool);
2428 #else  // format_args is passed by reference since it is defined later.
2429 inline void vprint_mojibake(FILE*, string_view, const format_args&, bool) {}
2430 #endif
2431 }  // namespace detail
2432 
2433 // The main public API.
2434 
2435 template <typename Char>
2436 FMT_CONSTEXPR void parse_context<Char>::do_check_arg_id(int arg_id) {
2437   // Argument id is only checked at compile time during parsing because
2438   // formatting has its own validation.
2439   if (detail::is_constant_evaluated() && use_constexpr_cast) {
2440     auto ctx = static_cast<detail::compile_parse_context<Char>*>(this);
2441     if (arg_id >= ctx->num_args()) report_error("argument not found");
2442   }
2443 }
2444 
2445 template <typename Char>
2446 FMT_CONSTEXPR void parse_context<Char>::check_dynamic_spec(int arg_id) {
2447   using detail::compile_parse_context;
2448   if (detail::is_constant_evaluated() && use_constexpr_cast)
2449     static_cast<compile_parse_context<Char>*>(this)->check_dynamic_spec(arg_id);
2450 }
2451 
2452 FMT_BEGIN_EXPORT
2453 
2454 // An output iterator that appends to a buffer. It is used instead of
2455 // back_insert_iterator to reduce symbol sizes and avoid <iterator> dependency.
2456 template <typename T> class basic_appender {
2457  protected:
2458   detail::buffer<T>* container;
2459 
2460  public:
2461   using container_type = detail::buffer<T>;
2462 
2463   FMT_CONSTEXPR basic_appender(detail::buffer<T>& buf) : container(&buf) {}
2464 
2465   FMT_CONSTEXPR20 auto operator=(T c) -> basic_appender& {
2466     container->push_back(c);
2467     return *this;
2468   }
2469   FMT_CONSTEXPR20 auto operator*() -> basic_appender& { return *this; }
2470   FMT_CONSTEXPR20 auto operator++() -> basic_appender& { return *this; }
2471   FMT_CONSTEXPR20 auto operator++(int) -> basic_appender { return *this; }
2472 };
2473 
2474 // A formatting argument. Context is a template parameter for the compiled API
2475 // where output can be unbuffered.
2476 template <typename Context> class basic_format_arg {
2477  private:
2478   detail::value<Context> value_;
2479   detail::type type_;
2480 
2481   friend class basic_format_args<Context>;
2482 
2483   using char_type = typename Context::char_type;
2484 
2485  public:
2486   class handle {
2487    private:
2488     detail::custom_value<Context> custom_;
2489 
2490    public:
2491     explicit handle(detail::custom_value<Context> custom) : custom_(custom) {}
2492 
2493     void format(parse_context<char_type>& parse_ctx, Context& ctx) const {
2494       custom_.format(custom_.value, parse_ctx, ctx);
2495     }
2496   };
2497 
2498   constexpr basic_format_arg() : type_(detail::type::none_type) {}
2499   basic_format_arg(const detail::named_arg_info<char_type>* args, size_t size)
2500       : value_(args, size) {}
2501   template <typename T>
2502   basic_format_arg(T&& val)
2503       : value_(val), type_(detail::stored_type_constant<T, Context>::value) {}
2504 
2505   constexpr explicit operator bool() const noexcept {
2506     return type_ != detail::type::none_type;
2507   }
2508   auto type() const -> detail::type { return type_; }
2509 
2510   /**
2511    * Visits an argument dispatching to the appropriate visit method based on
2512    * the argument type. For example, if the argument type is `double` then
2513    * `vis(value)` will be called with the value of type `double`.
2514    */
2515   template <typename Visitor>
2516   FMT_CONSTEXPR FMT_INLINE auto visit(Visitor&& vis) const -> decltype(vis(0)) {
2517     using detail::map;
2518     switch (type_) {
2519     case detail::type::none_type:        break;
2520     case detail::type::int_type:         return vis(value_.int_value);
2521     case detail::type::uint_type:        return vis(value_.uint_value);
2522     case detail::type::long_long_type:   return vis(value_.long_long_value);
2523     case detail::type::ulong_long_type:  return vis(value_.ulong_long_value);
2524     case detail::type::int128_type:      return vis(map(value_.int128_value));
2525     case detail::type::uint128_type:     return vis(map(value_.uint128_value));
2526     case detail::type::bool_type:        return vis(value_.bool_value);
2527     case detail::type::char_type:        return vis(value_.char_value);
2528     case detail::type::float_type:       return vis(value_.float_value);
2529     case detail::type::double_type:      return vis(value_.double_value);
2530     case detail::type::long_double_type: return vis(value_.long_double_value);
2531     case detail::type::cstring_type:     return vis(value_.string.data);
2532     case detail::type::string_type:      return vis(value_.string.str());
2533     case detail::type::pointer_type:     return vis(value_.pointer);
2534     case detail::type::custom_type:      return vis(handle(value_.custom));
2535     }
2536     return vis(monostate());
2537   }
2538 
2539   auto format_custom(const char_type* parse_begin,
2540                      parse_context<char_type>& parse_ctx, Context& ctx)
2541       -> bool {
2542     if (type_ != detail::type::custom_type) return false;
2543     parse_ctx.advance_to(parse_begin);
2544     value_.custom.format(value_.custom.value, parse_ctx, ctx);
2545     return true;
2546   }
2547 };
2548 
2549 /**
2550  * A view of a collection of formatting arguments. To avoid lifetime issues it
2551  * should only be used as a parameter type in type-erased functions such as
2552  * `vformat`:
2553  *
2554  *     void vlog(fmt::string_view fmt, fmt::format_args args);  // OK
2555  *     fmt::format_args args = fmt::make_format_args();  // Dangling reference
2556  */
2557 template <typename Context> class basic_format_args {
2558  private:
2559   // A descriptor that contains information about formatting arguments.
2560   // If the number of arguments is less or equal to max_packed_args then
2561   // argument types are passed in the descriptor. This reduces binary code size
2562   // per formatting function call.
2563   unsigned long long desc_;
2564   union {
2565     // If is_packed() returns true then argument values are stored in values_;
2566     // otherwise they are stored in args_. This is done to improve cache
2567     // locality and reduce compiled code size since storing larger objects
2568     // may require more code (at least on x86-64) even if the same amount of
2569     // data is actually copied to stack. It saves ~10% on the bloat test.
2570     const detail::value<Context>* values_;
2571     const basic_format_arg<Context>* args_;
2572   };
2573 
2574   constexpr auto is_packed() const -> bool {
2575     return (desc_ & detail::is_unpacked_bit) == 0;
2576   }
2577   constexpr auto has_named_args() const -> bool {
2578     return (desc_ & detail::has_named_args_bit) != 0;
2579   }
2580 
2581   FMT_CONSTEXPR auto type(int index) const -> detail::type {
2582     int shift = index * detail::packed_arg_bits;
2583     unsigned mask = (1 << detail::packed_arg_bits) - 1;
2584     return static_cast<detail::type>((desc_ >> shift) & mask);
2585   }
2586 
2587   template <int NUM_ARGS, int NUM_NAMED_ARGS, unsigned long long DESC>
2588   using store =
2589       detail::format_arg_store<Context, NUM_ARGS, NUM_NAMED_ARGS, DESC>;
2590 
2591  public:
2592   using format_arg = basic_format_arg<Context>;
2593 
2594   constexpr basic_format_args() : desc_(0), args_(nullptr) {}
2595 
2596   /// Constructs a `basic_format_args` object from `format_arg_store`.
2597   template <int NUM_ARGS, int NUM_NAMED_ARGS, unsigned long long DESC,
2598             FMT_ENABLE_IF(NUM_ARGS <= detail::max_packed_args)>
2599   constexpr FMT_ALWAYS_INLINE basic_format_args(
2600       const store<NUM_ARGS, NUM_NAMED_ARGS, DESC>& s)
2601       : desc_(DESC | (NUM_NAMED_ARGS != 0 ? +detail::has_named_args_bit : 0)),
2602         values_(s.args) {}
2603 
2604   template <int NUM_ARGS, int NUM_NAMED_ARGS, unsigned long long DESC,
2605             FMT_ENABLE_IF(NUM_ARGS > detail::max_packed_args)>
2606   constexpr basic_format_args(const store<NUM_ARGS, NUM_NAMED_ARGS, DESC>& s)
2607       : desc_(DESC | (NUM_NAMED_ARGS != 0 ? +detail::has_named_args_bit : 0)),
2608         args_(s.args) {}
2609 
2610   /// Constructs a `basic_format_args` object from a dynamic list of arguments.
2611   constexpr basic_format_args(const format_arg* args, int count,
2612                               bool has_named = false)
2613       : desc_(detail::is_unpacked_bit | detail::to_unsigned(count) |
2614               (has_named ? +detail::has_named_args_bit : 0)),
2615         args_(args) {}
2616 
2617   /// Returns the argument with the specified id.
2618   FMT_CONSTEXPR auto get(int id) const -> format_arg {
2619     auto arg = format_arg();
2620     if (!is_packed()) {
2621       if (id < max_size()) arg = args_[id];
2622       return arg;
2623     }
2624     if (static_cast<unsigned>(id) >= detail::max_packed_args) return arg;
2625     arg.type_ = type(id);
2626     if (arg.type_ != detail::type::none_type) arg.value_ = values_[id];
2627     return arg;
2628   }
2629 
2630   template <typename Char>
2631   auto get(basic_string_view<Char> name) const -> format_arg {
2632     int id = get_id(name);
2633     return id >= 0 ? get(id) : format_arg();
2634   }
2635 
2636   template <typename Char>
2637   FMT_CONSTEXPR auto get_id(basic_string_view<Char> name) const -> int {
2638     if (!has_named_args()) return -1;
2639     const auto& named_args =
2640         (is_packed() ? values_[-1] : args_[-1].value_).named_args;
2641     for (size_t i = 0; i < named_args.size; ++i) {
2642       if (named_args.data[i].name == name) return named_args.data[i].id;
2643     }
2644     return -1;
2645   }
2646 
2647   auto max_size() const -> int {
2648     unsigned long long max_packed = detail::max_packed_args;
2649     return static_cast<int>(is_packed() ? max_packed
2650                                         : desc_ & ~detail::is_unpacked_bit);
2651   }
2652 };
2653 
2654 // A formatting context.
2655 class context {
2656  private:
2657   appender out_;
2658   format_args args_;
2659   FMT_NO_UNIQUE_ADDRESS detail::locale_ref loc_;
2660 
2661  public:
2662   /// The character type for the output.
2663   using char_type = char;
2664 
2665   using iterator = appender;
2666   using format_arg = basic_format_arg<context>;
2667   using parse_context_type FMT_DEPRECATED = parse_context<>;
2668   template <typename T> using formatter_type FMT_DEPRECATED = formatter<T>;
2669   enum { builtin_types = FMT_BUILTIN_TYPES };
2670 
2671   /// Constructs a `context` object. References to the arguments are stored
2672   /// in the object so make sure they have appropriate lifetimes.
2673   FMT_CONSTEXPR context(iterator out, format_args args,
2674                         detail::locale_ref loc = {})
2675       : out_(out), args_(args), loc_(loc) {}
2676   context(context&&) = default;
2677   context(const context&) = delete;
2678   void operator=(const context&) = delete;
2679 
2680   FMT_CONSTEXPR auto arg(int id) const -> format_arg { return args_.get(id); }
2681   inline auto arg(string_view name) const -> format_arg {
2682     return args_.get(name);
2683   }
2684   FMT_CONSTEXPR auto arg_id(string_view name) const -> int {
2685     return args_.get_id(name);
2686   }
2687   auto args() const -> const format_args& { return args_; }
2688 
2689   // Returns an iterator to the beginning of the output range.
2690   FMT_CONSTEXPR auto out() const -> iterator { return out_; }
2691 
2692   // Advances the begin iterator to `it`.
2693   FMT_CONSTEXPR void advance_to(iterator) {}
2694 
2695   FMT_CONSTEXPR auto locale() const -> detail::locale_ref { return loc_; }
2696 };
2697 
2698 template <typename Char = char> struct runtime_format_string {
2699   basic_string_view<Char> str;
2700 };
2701 
2702 /**
2703  * Creates a runtime format string.
2704  *
2705  * **Example**:
2706  *
2707  *     // Check format string at runtime instead of compile-time.
2708  *     fmt::print(fmt::runtime("{:d}"), "I am not a number");
2709  */
2710 inline auto runtime(string_view s) -> runtime_format_string<> { return {{s}}; }
2711 
2712 /// A compile-time format string. Use `format_string` in the public API to
2713 /// prevent type deduction.
2714 template <typename... T> struct fstring {
2715  private:
2716   static constexpr int num_static_named_args =
2717       detail::count_static_named_args<T...>();
2718 
2719   using checker = detail::format_string_checker<
2720       char, static_cast<int>(sizeof...(T)), num_static_named_args,
2721       num_static_named_args != detail::count_named_args<T...>()>;
2722 
2723   using arg_pack = detail::arg_pack<T...>;
2724 
2725  public:
2726   string_view str;
2727   using t = fstring;
2728 
2729   // Reports a compile-time error if S is not a valid format string for T.
2730   template <size_t N>
2731   FMT_CONSTEVAL FMT_ALWAYS_INLINE fstring(const char (&s)[N]) : str(s, N - 1) {
2732     using namespace detail;
2733     static_assert(count<(is_view<remove_cvref_t<T>>::value &&
2734                          std::is_reference<T>::value)...>() == 0,
2735                   "passing views as lvalues is disallowed");
2736     if (FMT_USE_CONSTEVAL) parse_format_string<char>(s, checker(s, arg_pack()));
2737 #ifdef FMT_ENFORCE_COMPILE_STRING
2738     static_assert(
2739         FMT_USE_CONSTEVAL && sizeof(s) != 0,
2740         "FMT_ENFORCE_COMPILE_STRING requires format strings to use FMT_STRING");
2741 #endif
2742   }
2743   template <typename S,
2744             FMT_ENABLE_IF(std::is_convertible<const S&, string_view>::value)>
2745   FMT_CONSTEVAL FMT_ALWAYS_INLINE fstring(const S& s) : str(s) {
2746     auto sv = string_view(str);
2747     if (FMT_USE_CONSTEVAL)
2748       detail::parse_format_string<char>(sv, checker(sv, arg_pack()));
2749 #ifdef FMT_ENFORCE_COMPILE_STRING
2750     static_assert(
2751         FMT_USE_CONSTEVAL && sizeof(s) != 0,
2752         "FMT_ENFORCE_COMPILE_STRING requires format strings to use FMT_STRING");
2753 #endif
2754   }
2755   template <typename S,
2756             FMT_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&&
2757                               std::is_same<typename S::char_type, char>::value)>
2758   FMT_ALWAYS_INLINE fstring(const S&) : str(S()) {
2759     FMT_CONSTEXPR auto sv = string_view(S());
2760     FMT_CONSTEXPR int unused =
2761         (parse_format_string(sv, checker(sv, arg_pack())), 0);
2762     detail::ignore_unused(unused);
2763   }
2764   fstring(runtime_format_string<> fmt) : str(fmt.str) {}
2765 
2766   // Returning by reference generates better code in debug mode.
2767   FMT_ALWAYS_INLINE operator const string_view&() const { return str; }
2768   auto get() const -> string_view { return str; }
2769 };
2770 
2771 template <typename... T> using format_string = typename fstring<T...>::t;
2772 
2773 template <typename T, typename Char = char>
2774 using is_formattable = bool_constant<!std::is_same<
2775     detail::mapped_t<conditional_t<std::is_void<T>::value, int*, T>, Char>,
2776     void>::value>;
2777 #ifdef __cpp_concepts
2778 template <typename T, typename Char = char>
2779 concept formattable = is_formattable<remove_reference_t<T>, Char>::value;
2780 #endif
2781 
2782 template <typename T, typename Char>
2783 using has_formatter FMT_DEPRECATED = std::is_constructible<formatter<T, Char>>;
2784 
2785 // A formatter specialization for natively supported types.
2786 template <typename T, typename Char>
2787 struct formatter<T, Char,
2788                  enable_if_t<detail::type_constant<T, Char>::value !=
2789                              detail::type::custom_type>>
2790     : detail::native_formatter<T, Char, detail::type_constant<T, Char>::value> {
2791 };
2792 
2793 /**
2794  * Constructs an object that stores references to arguments and can be
2795  * implicitly converted to `format_args`. `Context` can be omitted in which case
2796  * it defaults to `context`. See `arg` for lifetime considerations.
2797  */
2798 // Take arguments by lvalue references to avoid some lifetime issues, e.g.
2799 //   auto args = make_format_args(std::string());
2800 template <typename Context = context, typename... T,
2801           int NUM_ARGS = sizeof...(T),
2802           int NUM_NAMED_ARGS = detail::count_named_args<T...>(),
2803           unsigned long long DESC = detail::make_descriptor<Context, T...>()>
2804 constexpr FMT_ALWAYS_INLINE auto make_format_args(T&... args)
2805     -> detail::format_arg_store<Context, NUM_ARGS, NUM_NAMED_ARGS, DESC> {
2806   // Suppress warnings for pathological types convertible to detail::value.
2807   FMT_PRAGMA_GCC(diagnostic ignored "-Wconversion")
2808   return {{args...}};
2809 }
2810 
2811 template <typename... T>
2812 using vargs =
2813     detail::format_arg_store<context, sizeof...(T),
2814                              detail::count_named_args<T...>(),
2815                              detail::make_descriptor<context, T...>()>;
2816 
2817 /**
2818  * Returns a named argument to be used in a formatting function.
2819  * It should only be used in a call to a formatting function.
2820  *
2821  * **Example**:
2822  *
2823  *     fmt::print("The answer is {answer}.", fmt::arg("answer", 42));
2824  */
2825 template <typename Char, typename T>
2826 inline auto arg(const Char* name, const T& arg) -> detail::named_arg<Char, T> {
2827   return {name, arg};
2828 }
2829 
2830 /// Formats a string and writes the output to `out`.
2831 template <typename OutputIt,
2832           FMT_ENABLE_IF(detail::is_output_iterator<remove_cvref_t<OutputIt>,
2833                                                    char>::value)>
2834 auto vformat_to(OutputIt&& out, string_view fmt, format_args args)
2835     -> remove_cvref_t<OutputIt> {
2836   auto&& buf = detail::get_buffer<char>(out);
2837   detail::vformat_to(buf, fmt, args, {});
2838   return detail::get_iterator(buf, out);
2839 }
2840 
2841 /**
2842  * Formats `args` according to specifications in `fmt`, writes the result to
2843  * the output iterator `out` and returns the iterator past the end of the output
2844  * range. `format_to` does not append a terminating null character.
2845  *
2846  * **Example**:
2847  *
2848  *     auto out = std::vector<char>();
2849  *     fmt::format_to(std::back_inserter(out), "{}", 42);
2850  */
2851 template <typename OutputIt, typename... T,
2852           FMT_ENABLE_IF(detail::is_output_iterator<remove_cvref_t<OutputIt>,
2853                                                    char>::value)>
2854 FMT_INLINE auto format_to(OutputIt&& out, format_string<T...> fmt, T&&... args)
2855     -> remove_cvref_t<OutputIt> {
2856   return vformat_to(out, fmt.str, vargs<T...>{{args...}});
2857 }
2858 
2859 template <typename OutputIt> struct format_to_n_result {
2860   /// Iterator past the end of the output range.
2861   OutputIt out;
2862   /// Total (not truncated) output size.
2863   size_t size;
2864 };
2865 
2866 template <typename OutputIt, typename... T,
2867           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
2868 auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args)
2869     -> format_to_n_result<OutputIt> {
2870   using traits = detail::fixed_buffer_traits;
2871   auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
2872   detail::vformat_to(buf, fmt, args, {});
2873   return {buf.out(), buf.count()};
2874 }
2875 
2876 /**
2877  * Formats `args` according to specifications in `fmt`, writes up to `n`
2878  * characters of the result to the output iterator `out` and returns the total
2879  * (not truncated) output size and the iterator past the end of the output
2880  * range. `format_to_n` does not append a terminating null character.
2881  */
2882 template <typename OutputIt, typename... T,
2883           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
2884 FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string<T...> fmt,
2885                             T&&... args) -> format_to_n_result<OutputIt> {
2886   return vformat_to_n(out, n, fmt.str, vargs<T...>{{args...}});
2887 }
2888 
2889 struct format_to_result {
2890   /// Pointer to just after the last successful write in the array.
2891   char* out;
2892   /// Specifies if the output was truncated.
2893   bool truncated;
2894 
2895   FMT_CONSTEXPR operator char*() const {
2896     // Report truncation to prevent silent data loss.
2897     if (truncated) report_error("output is truncated");
2898     return out;
2899   }
2900 };
2901 
2902 template <size_t N>
2903 auto vformat_to(char (&out)[N], string_view fmt, format_args args)
2904     -> format_to_result {
2905   auto result = vformat_to_n(out, N, fmt, args);
2906   return {result.out, result.size > N};
2907 }
2908 
2909 template <size_t N, typename... T>
2910 FMT_INLINE auto format_to(char (&out)[N], format_string<T...> fmt, T&&... args)
2911     -> format_to_result {
2912   auto result = vformat_to_n(out, N, fmt.str, vargs<T...>{{args...}});
2913   return {result.out, result.size > N};
2914 }
2915 
2916 /// Returns the number of chars in the output of `format(fmt, args...)`.
2917 template <typename... T>
2918 FMT_NODISCARD FMT_INLINE auto formatted_size(format_string<T...> fmt,
2919                                              T&&... args) -> size_t {
2920   auto buf = detail::counting_buffer<>();
2921   detail::vformat_to(buf, fmt.str, vargs<T...>{{args...}}, {});
2922   return buf.count();
2923 }
2924 
2925 FMT_API void vprint(string_view fmt, format_args args);
2926 FMT_API void vprint(FILE* f, string_view fmt, format_args args);
2927 FMT_API void vprintln(FILE* f, string_view fmt, format_args args);
2928 FMT_API void vprint_buffered(FILE* f, string_view fmt, format_args args);
2929 
2930 /**
2931  * Formats `args` according to specifications in `fmt` and writes the output
2932  * to `stdout`.
2933  *
2934  * **Example**:
2935  *
2936  *     fmt::print("The answer is {}.", 42);
2937  */
2938 template <typename... T>
2939 FMT_INLINE void print(format_string<T...> fmt, T&&... args) {
2940   vargs<T...> va = {{args...}};
2941   if (detail::const_check(!detail::use_utf8))
2942     return detail::vprint_mojibake(stdout, fmt.str, va, false);
2943   return detail::is_locking<T...>() ? vprint_buffered(stdout, fmt.str, va)
2944                                     : vprint(fmt.str, va);
2945 }
2946 
2947 /**
2948  * Formats `args` according to specifications in `fmt` and writes the
2949  * output to the file `f`.
2950  *
2951  * **Example**:
2952  *
2953  *     fmt::print(stderr, "Don't {}!", "panic");
2954  */
2955 template <typename... T>
2956 FMT_INLINE void print(FILE* f, format_string<T...> fmt, T&&... args) {
2957   vargs<T...> va = {{args...}};
2958   if (detail::const_check(!detail::use_utf8))
2959     return detail::vprint_mojibake(f, fmt.str, va, false);
2960   return detail::is_locking<T...>() ? vprint_buffered(f, fmt.str, va)
2961                                     : vprint(f, fmt.str, va);
2962 }
2963 
2964 /// Formats `args` according to specifications in `fmt` and writes the output
2965 /// to the file `f` followed by a newline.
2966 template <typename... T>
2967 FMT_INLINE void println(FILE* f, format_string<T...> fmt, T&&... args) {
2968   vargs<T...> va = {{args...}};
2969   return detail::const_check(detail::use_utf8)
2970              ? vprintln(f, fmt.str, va)
2971              : detail::vprint_mojibake(f, fmt.str, va, true);
2972 }
2973 
2974 /// Formats `args` according to specifications in `fmt` and writes the output
2975 /// to `stdout` followed by a newline.
2976 template <typename... T>
2977 FMT_INLINE void println(format_string<T...> fmt, T&&... args) {
2978   return fmt::println(stdout, fmt, static_cast<T&&>(args)...);
2979 }
2980 
2981 FMT_END_EXPORT
2982 FMT_PRAGMA_CLANG(diagnostic pop)
2983 FMT_PRAGMA_GCC(pop_options)
2984 FMT_END_NAMESPACE
2985 
2986 #ifdef FMT_HEADER_ONLY
2987 #  include "format.h"
2988 #endif
2989 #endif  // FMT_BASE_H_