• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2   Formatting library for C++
3 
4   Copyright (c) 2012 - present, Victor Zverovich
5 
6   Permission is hereby granted, free of charge, to any person obtaining
7   a copy of this software and associated documentation files (the
8   "Software"), to deal in the Software without restriction, including
9   without limitation the rights to use, copy, modify, merge, publish,
10   distribute, sublicense, and/or sell copies of the Software, and to
11   permit persons to whom the Software is furnished to do so, subject to
12   the following conditions:
13 
14   The above copyright notice and this permission notice shall be
15   included in all copies or substantial portions of the Software.
16 
17   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25   --- Optional exception to the license ---
26 
27   As an exception, if, as a result of your compiling your source code, portions
28   of this Software are embedded into a machine-executable object form of such
29   source code, you may redistribute such embedded portions in such object form
30   without including the above copyright and permission notices.
31  */
32 
33 #ifndef FMT_FORMAT_H_
34 #define FMT_FORMAT_H_
35 
36 #include <cmath>             // std::signbit
37 #include <cstdint>           // uint32_t
38 #include <cstring>           // std::memcpy
39 #include <initializer_list>  // std::initializer_list
40 #include <limits>            // std::numeric_limits
41 #include <memory>            // std::uninitialized_copy
42 #include <stdexcept>         // std::runtime_error
43 #include <system_error>      // std::system_error
44 
45 #ifdef __cpp_lib_bit_cast
46 #  include <bit>  // std::bit_cast
47 #endif
48 
49 #include "core.h"
50 
51 #if defined __cpp_inline_variables && __cpp_inline_variables >= 201606L
52 #  define FMT_INLINE_VARIABLE inline
53 #else
54 #  define FMT_INLINE_VARIABLE
55 #endif
56 
57 #if FMT_HAS_CPP17_ATTRIBUTE(fallthrough)
58 #  define FMT_FALLTHROUGH [[fallthrough]]
59 #elif defined(__clang__)
60 #  define FMT_FALLTHROUGH [[clang::fallthrough]]
61 #elif FMT_GCC_VERSION >= 700 && \
62     (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520)
63 #  define FMT_FALLTHROUGH [[gnu::fallthrough]]
64 #else
65 #  define FMT_FALLTHROUGH
66 #endif
67 
68 #ifndef FMT_DEPRECATED
69 #  if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VERSION >= 1900
70 #    define FMT_DEPRECATED [[deprecated]]
71 #  else
72 #    if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
73 #      define FMT_DEPRECATED __attribute__((deprecated))
74 #    elif FMT_MSC_VERSION
75 #      define FMT_DEPRECATED __declspec(deprecated)
76 #    else
77 #      define FMT_DEPRECATED /* deprecated */
78 #    endif
79 #  endif
80 #endif
81 
82 #ifndef FMT_NO_UNIQUE_ADDRESS
83 #  if FMT_CPLUSPLUS >= 202002L
84 #    if FMT_HAS_CPP_ATTRIBUTE(no_unique_address)
85 #      define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]]
86 // VS2019 v16.10 and later except clang-cl (https://reviews.llvm.org/D110485)
87 #    elif (FMT_MSC_VERSION >= 1929) && !FMT_CLANG_VERSION
88 #      define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
89 #    endif
90 #  endif
91 #endif
92 #ifndef FMT_NO_UNIQUE_ADDRESS
93 #  define FMT_NO_UNIQUE_ADDRESS
94 #endif
95 
96 // Visibility when compiled as a shared library/object.
97 #if defined(FMT_LIB_EXPORT) || defined(FMT_SHARED)
98 #  define FMT_SO_VISIBILITY(value) FMT_VISIBILITY(value)
99 #else
100 #  define FMT_SO_VISIBILITY(value)
101 #endif
102 
103 #ifdef __has_builtin
104 #  define FMT_HAS_BUILTIN(x) __has_builtin(x)
105 #else
106 #  define FMT_HAS_BUILTIN(x) 0
107 #endif
108 
109 #if FMT_GCC_VERSION || FMT_CLANG_VERSION
110 #  define FMT_NOINLINE __attribute__((noinline))
111 #else
112 #  define FMT_NOINLINE
113 #endif
114 
115 #ifndef FMT_THROW
116 #  if FMT_EXCEPTIONS
117 #    if FMT_MSC_VERSION || defined(__NVCC__)
118 FMT_BEGIN_NAMESPACE
119 namespace detail {
do_throw(const Exception & x)120 template <typename Exception> inline void do_throw(const Exception& x) {
121   // Silence unreachable code warnings in MSVC and NVCC because these
122   // are nearly impossible to fix in a generic code.
123   volatile bool b = true;
124   if (b) throw x;
125 }
126 }  // namespace detail
127 FMT_END_NAMESPACE
128 #      define FMT_THROW(x) detail::do_throw(x)
129 #    else
130 #      define FMT_THROW(x) throw x
131 #    endif
132 #  else
133 #    define FMT_THROW(x) \
134       ::fmt::detail::assert_fail(__FILE__, __LINE__, (x).what())
135 #  endif
136 #endif
137 
138 #if FMT_EXCEPTIONS
139 #  define FMT_TRY try
140 #  define FMT_CATCH(x) catch (x)
141 #else
142 #  define FMT_TRY if (true)
143 #  define FMT_CATCH(x) if (false)
144 #endif
145 
146 #ifndef FMT_MAYBE_UNUSED
147 #  if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused)
148 #    define FMT_MAYBE_UNUSED [[maybe_unused]]
149 #  else
150 #    define FMT_MAYBE_UNUSED
151 #  endif
152 #endif
153 
154 #ifndef FMT_USE_USER_DEFINED_LITERALS
155 // EDG based compilers (Intel, NVIDIA, Elbrus, etc), GCC and MSVC support UDLs.
156 //
157 // GCC before 4.9 requires a space in `operator"" _a` which is invalid in later
158 // compiler versions.
159 #  if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 409 || \
160        FMT_MSC_VERSION >= 1900) &&                                     \
161       (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= /* UDL feature */ 480)
162 #    define FMT_USE_USER_DEFINED_LITERALS 1
163 #  else
164 #    define FMT_USE_USER_DEFINED_LITERALS 0
165 #  endif
166 #endif
167 
168 // Defining FMT_REDUCE_INT_INSTANTIATIONS to 1, will reduce the number of
169 // integer formatter template instantiations to just one by only using the
170 // largest integer type. This results in a reduction in binary size but will
171 // cause a decrease in integer formatting performance.
172 #if !defined(FMT_REDUCE_INT_INSTANTIATIONS)
173 #  define FMT_REDUCE_INT_INSTANTIATIONS 0
174 #endif
175 
176 // __builtin_clz is broken in clang with Microsoft CodeGen:
177 // https://github.com/fmtlib/fmt/issues/519.
178 #if !FMT_MSC_VERSION
179 #  if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION
180 #    define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
181 #  endif
182 #  if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION
183 #    define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
184 #  endif
185 #endif
186 
187 // __builtin_ctz is broken in Intel Compiler Classic on Windows:
188 // https://github.com/fmtlib/fmt/issues/2510.
189 #ifndef __ICL
190 #  if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION || \
191       defined(__NVCOMPILER)
192 #    define FMT_BUILTIN_CTZ(n) __builtin_ctz(n)
193 #  endif
194 #  if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || \
195       FMT_ICC_VERSION || defined(__NVCOMPILER)
196 #    define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n)
197 #  endif
198 #endif
199 
200 #if FMT_MSC_VERSION
201 #  include <intrin.h>  // _BitScanReverse[64], _BitScanForward[64], _umul128
202 #endif
203 
204 // Some compilers masquerade as both MSVC and GCC-likes or otherwise support
205 // __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the
206 // MSVC intrinsics if the clz and clzll builtins are not available.
207 #if FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) && \
208     !defined(FMT_BUILTIN_CTZLL)
209 FMT_BEGIN_NAMESPACE
210 namespace detail {
211 // Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning.
212 #  if !defined(__clang__)
213 #    pragma intrinsic(_BitScanForward)
214 #    pragma intrinsic(_BitScanReverse)
215 #    if defined(_WIN64)
216 #      pragma intrinsic(_BitScanForward64)
217 #      pragma intrinsic(_BitScanReverse64)
218 #    endif
219 #  endif
220 
221 inline auto clz(uint32_t x) -> int {
222   unsigned long r = 0;
223   _BitScanReverse(&r, x);
224   FMT_ASSERT(x != 0, "");
225   // Static analysis complains about using uninitialized data
226   // "r", but the only way that can happen is if "x" is 0,
227   // which the callers guarantee to not happen.
228   FMT_MSC_WARNING(suppress : 6102)
229   return 31 ^ static_cast<int>(r);
230 }
231 #  define FMT_BUILTIN_CLZ(n) detail::clz(n)
232 
233 inline auto clzll(uint64_t x) -> int {
234   unsigned long r = 0;
235 #  ifdef _WIN64
236   _BitScanReverse64(&r, x);
237 #  else
238   // Scan the high 32 bits.
239   if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
240     return 63 ^ static_cast<int>(r + 32);
241   // Scan the low 32 bits.
242   _BitScanReverse(&r, static_cast<uint32_t>(x));
243 #  endif
244   FMT_ASSERT(x != 0, "");
245   FMT_MSC_WARNING(suppress : 6102)  // Suppress a bogus static analysis warning.
246   return 63 ^ static_cast<int>(r);
247 }
248 #  define FMT_BUILTIN_CLZLL(n) detail::clzll(n)
249 
250 inline auto ctz(uint32_t x) -> int {
251   unsigned long r = 0;
252   _BitScanForward(&r, x);
253   FMT_ASSERT(x != 0, "");
254   FMT_MSC_WARNING(suppress : 6102)  // Suppress a bogus static analysis warning.
255   return static_cast<int>(r);
256 }
257 #  define FMT_BUILTIN_CTZ(n) detail::ctz(n)
258 
259 inline auto ctzll(uint64_t x) -> int {
260   unsigned long r = 0;
261   FMT_ASSERT(x != 0, "");
262   FMT_MSC_WARNING(suppress : 6102)  // Suppress a bogus static analysis warning.
263 #  ifdef _WIN64
264   _BitScanForward64(&r, x);
265 #  else
266   // Scan the low 32 bits.
267   if (_BitScanForward(&r, static_cast<uint32_t>(x))) return static_cast<int>(r);
268   // Scan the high 32 bits.
269   _BitScanForward(&r, static_cast<uint32_t>(x >> 32));
270   r += 32;
271 #  endif
272   return static_cast<int>(r);
273 }
274 #  define FMT_BUILTIN_CTZLL(n) detail::ctzll(n)
275 }  // namespace detail
276 FMT_END_NAMESPACE
277 #endif
278 
279 FMT_BEGIN_NAMESPACE
280 namespace detail {
281 
abort_fuzzing_if(bool condition)282 FMT_CONSTEXPR inline void abort_fuzzing_if(bool condition) {
283   ignore_unused(condition);
284 #ifdef FMT_FUZZ
285   if (condition) throw std::runtime_error("fuzzing limit reached");
286 #endif
287 }
288 
289 template <typename CharT, CharT... C> struct string_literal {
290   static constexpr CharT value[sizeof...(C)] = {C...};
291   constexpr operator basic_string_view<CharT>() const {
292     return {value, sizeof...(C)};
293   }
294 };
295 
296 #if FMT_CPLUSPLUS < 201703L
297 template <typename CharT, CharT... C>
298 constexpr CharT string_literal<CharT, C...>::value[sizeof...(C)];
299 #endif
300 
301 // Implementation of std::bit_cast for pre-C++20.
302 template <typename To, typename From, FMT_ENABLE_IF(sizeof(To) == sizeof(From))>
303 FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To {
304 #ifdef __cpp_lib_bit_cast
305   if (is_constant_evaluated()) return std::bit_cast<To>(from);
306 #endif
307   auto to = To();
308   // The cast suppresses a bogus -Wclass-memaccess on GCC.
309   std::memcpy(static_cast<void*>(&to), &from, sizeof(to));
310   return to;
311 }
312 
313 inline auto is_big_endian() -> bool {
314 #ifdef _WIN32
315   return false;
316 #elif defined(__BIG_ENDIAN__)
317   return true;
318 #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
319   return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;
320 #else
321   struct bytes {
322     char data[sizeof(int)];
323   };
324   return bit_cast<bytes>(1).data[0] == 0;
325 #endif
326 }
327 
328 class uint128_fallback {
329  private:
330   uint64_t lo_, hi_;
331 
332  public:
uint128_fallback(uint64_t hi,uint64_t lo)333   constexpr uint128_fallback(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {}
lo_(value)334   constexpr uint128_fallback(uint64_t value = 0) : lo_(value), hi_(0) {}
335 
336   constexpr auto high() const noexcept -> uint64_t { return hi_; }
337   constexpr auto low() const noexcept -> uint64_t { return lo_; }
338 
339   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
T()340   constexpr explicit operator T() const {
341     return static_cast<T>(lo_);
342   }
343 
344   friend constexpr auto operator==(const uint128_fallback& lhs,
345                                    const uint128_fallback& rhs) -> bool {
346     return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_;
347   }
348   friend constexpr auto operator!=(const uint128_fallback& lhs,
349                                    const uint128_fallback& rhs) -> bool {
350     return !(lhs == rhs);
351   }
352   friend constexpr auto operator>(const uint128_fallback& lhs,
353                                   const uint128_fallback& rhs) -> bool {
354     return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_;
355   }
356   friend constexpr auto operator|(const uint128_fallback& lhs,
357                                   const uint128_fallback& rhs)
358       -> uint128_fallback {
359     return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_};
360   }
361   friend constexpr auto operator&(const uint128_fallback& lhs,
362                                   const uint128_fallback& rhs)
363       -> uint128_fallback {
364     return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_};
365   }
366   friend constexpr auto operator~(const uint128_fallback& n)
367       -> uint128_fallback {
368     return {~n.hi_, ~n.lo_};
369   }
370   friend auto operator+(const uint128_fallback& lhs,
371                         const uint128_fallback& rhs) -> uint128_fallback {
372     auto result = uint128_fallback(lhs);
373     result += rhs;
374     return result;
375   }
376   friend auto operator*(const uint128_fallback& lhs, uint32_t rhs)
377       -> uint128_fallback {
378     FMT_ASSERT(lhs.hi_ == 0, "");
379     uint64_t hi = (lhs.lo_ >> 32) * rhs;
380     uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs;
381     uint64_t new_lo = (hi << 32) + lo;
382     return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo};
383   }
384   friend auto operator-(const uint128_fallback& lhs, uint64_t rhs)
385       -> uint128_fallback {
386     return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs};
387   }
388   FMT_CONSTEXPR auto operator>>(int shift) const -> uint128_fallback {
389     if (shift == 64) return {0, hi_};
390     if (shift > 64) return uint128_fallback(0, hi_) >> (shift - 64);
391     return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)};
392   }
393   FMT_CONSTEXPR auto operator<<(int shift) const -> uint128_fallback {
394     if (shift == 64) return {lo_, 0};
395     if (shift > 64) return uint128_fallback(lo_, 0) << (shift - 64);
396     return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)};
397   }
398   FMT_CONSTEXPR auto operator>>=(int shift) -> uint128_fallback& {
399     return *this = *this >> shift;
400   }
401   FMT_CONSTEXPR void operator+=(uint128_fallback n) {
402     uint64_t new_lo = lo_ + n.lo_;
403     uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0);
404     FMT_ASSERT(new_hi >= hi_, "");
405     lo_ = new_lo;
406     hi_ = new_hi;
407   }
408   FMT_CONSTEXPR void operator&=(uint128_fallback n) {
409     lo_ &= n.lo_;
410     hi_ &= n.hi_;
411   }
412 
413   FMT_CONSTEXPR20 auto operator+=(uint64_t n) noexcept -> uint128_fallback& {
414     if (is_constant_evaluated()) {
415       lo_ += n;
416       hi_ += (lo_ < n ? 1 : 0);
417       return *this;
418     }
419 #if FMT_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__)
420     unsigned long long carry;
421     lo_ = __builtin_addcll(lo_, n, 0, &carry);
422     hi_ += carry;
423 #elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__)
424     unsigned long long result;
425     auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result);
426     lo_ = result;
427     hi_ += carry;
428 #elif defined(_MSC_VER) && defined(_M_X64)
429     auto carry = _addcarry_u64(0, lo_, n, &lo_);
430     _addcarry_u64(carry, hi_, 0, &hi_);
431 #else
432     lo_ += n;
433     hi_ += (lo_ < n ? 1 : 0);
434 #endif
435     return *this;
436   }
437 };
438 
439 using uint128_t = conditional_t<FMT_USE_INT128, uint128_opt, uint128_fallback>;
440 
441 #ifdef UINTPTR_MAX
442 using uintptr_t = ::uintptr_t;
443 #else
444 using uintptr_t = uint128_t;
445 #endif
446 
447 // Returns the largest possible value for type T. Same as
448 // std::numeric_limits<T>::max() but shorter and not affected by the max macro.
449 template <typename T> constexpr auto max_value() -> T {
450   return (std::numeric_limits<T>::max)();
451 }
452 template <typename T> constexpr auto num_bits() -> int {
453   return std::numeric_limits<T>::digits;
454 }
455 // std::numeric_limits<T>::digits may return 0 for 128-bit ints.
456 template <> constexpr auto num_bits<int128_opt>() -> int { return 128; }
457 template <> constexpr auto num_bits<uint128_t>() -> int { return 128; }
458 
459 // A heterogeneous bit_cast used for converting 96-bit long double to uint128_t
460 // and 128-bit pointers to uint128_fallback.
461 template <typename To, typename From, FMT_ENABLE_IF(sizeof(To) > sizeof(From))>
462 inline auto bit_cast(const From& from) -> To {
463   constexpr auto size = static_cast<int>(sizeof(From) / sizeof(unsigned));
464   struct data_t {
465     unsigned value[static_cast<unsigned>(size)];
466   } data = bit_cast<data_t>(from);
467   auto result = To();
468   if (const_check(is_big_endian())) {
469     for (int i = 0; i < size; ++i)
470       result = (result << num_bits<unsigned>()) | data.value[i];
471   } else {
472     for (int i = size - 1; i >= 0; --i)
473       result = (result << num_bits<unsigned>()) | data.value[i];
474   }
475   return result;
476 }
477 
478 template <typename UInt>
479 FMT_CONSTEXPR20 inline auto countl_zero_fallback(UInt n) -> int {
480   int lz = 0;
481   constexpr UInt msb_mask = static_cast<UInt>(1) << (num_bits<UInt>() - 1);
482   for (; (n & msb_mask) == 0; n <<= 1) lz++;
483   return lz;
484 }
485 
486 FMT_CONSTEXPR20 inline auto countl_zero(uint32_t n) -> int {
487 #ifdef FMT_BUILTIN_CLZ
488   if (!is_constant_evaluated()) return FMT_BUILTIN_CLZ(n);
489 #endif
490   return countl_zero_fallback(n);
491 }
492 
493 FMT_CONSTEXPR20 inline auto countl_zero(uint64_t n) -> int {
494 #ifdef FMT_BUILTIN_CLZLL
495   if (!is_constant_evaluated()) return FMT_BUILTIN_CLZLL(n);
496 #endif
497   return countl_zero_fallback(n);
498 }
499 
assume(bool condition)500 FMT_INLINE void assume(bool condition) {
501   (void)condition;
502 #if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION
503   __builtin_assume(condition);
504 #elif FMT_GCC_VERSION
505   if (!condition) __builtin_unreachable();
506 #endif
507 }
508 
509 // An approximation of iterator_t for pre-C++20 systems.
510 template <typename T>
511 using iterator_t = decltype(std::begin(std::declval<T&>()));
512 template <typename T> using sentinel_t = decltype(std::end(std::declval<T&>()));
513 
514 // A workaround for std::string not having mutable data() until C++17.
515 template <typename Char>
516 inline auto get_data(std::basic_string<Char>& s) -> Char* {
517   return &s[0];
518 }
519 template <typename Container>
520 inline auto get_data(Container& c) -> typename Container::value_type* {
521   return c.data();
522 }
523 
524 // Attempts to reserve space for n extra characters in the output range.
525 // Returns a pointer to the reserved range or a reference to it.
526 template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
527 #if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION
528 __attribute__((no_sanitize("undefined")))
529 #endif
530 inline auto
531 reserve(std::back_insert_iterator<Container> it, size_t n) ->
532     typename Container::value_type* {
533   Container& c = get_container(it);
534   size_t size = c.size();
535   c.resize(size + n);
536   return get_data(c) + size;
537 }
538 
539 template <typename T>
540 inline auto reserve(buffer_appender<T> it, size_t n) -> buffer_appender<T> {
541   buffer<T>& buf = get_container(it);
542   buf.try_reserve(buf.size() + n);
543   return it;
544 }
545 
546 template <typename Iterator>
547 constexpr auto reserve(Iterator& it, size_t) -> Iterator& {
548   return it;
549 }
550 
551 template <typename OutputIt>
552 using reserve_iterator =
553     remove_reference_t<decltype(reserve(std::declval<OutputIt&>(), 0))>;
554 
555 template <typename T, typename OutputIt>
556 constexpr auto to_pointer(OutputIt, size_t) -> T* {
557   return nullptr;
558 }
559 template <typename T> auto to_pointer(buffer_appender<T> it, size_t n) -> T* {
560   buffer<T>& buf = get_container(it);
561   auto size = buf.size();
562   if (buf.capacity() < size + n) return nullptr;
563   buf.try_resize(size + n);
564   return buf.data() + size;
565 }
566 
567 template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
568 inline auto base_iterator(std::back_insert_iterator<Container> it,
569                           typename Container::value_type*)
570     -> std::back_insert_iterator<Container> {
571   return it;
572 }
573 
574 template <typename Iterator>
575 constexpr auto base_iterator(Iterator, Iterator it) -> Iterator {
576   return it;
577 }
578 
579 // <algorithm> is spectacularly slow to compile in C++20 so use a simple fill_n
580 // instead (#1998).
581 template <typename OutputIt, typename Size, typename T>
582 FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T& value)
583     -> OutputIt {
584   for (Size i = 0; i < count; ++i) *out++ = value;
585   return out;
586 }
587 template <typename T, typename Size>
588 FMT_CONSTEXPR20 auto fill_n(T* out, Size count, char value) -> T* {
589   if (is_constant_evaluated()) {
590     return fill_n<T*, Size, T>(out, count, value);
591   }
592   std::memset(out, value, to_unsigned(count));
593   return out + count;
594 }
595 
596 #ifdef __cpp_char8_t
597 using char8_type = char8_t;
598 #else
599 enum char8_type : unsigned char {};
600 #endif
601 
602 template <typename OutChar, typename InputIt, typename OutputIt>
603 FMT_CONSTEXPR FMT_NOINLINE auto copy_str_noinline(InputIt begin, InputIt end,
604                                                   OutputIt out) -> OutputIt {
605   return copy_str<OutChar>(begin, end, out);
606 }
607 
608 // A public domain branchless UTF-8 decoder by Christopher Wellons:
609 // https://github.com/skeeto/branchless-utf8
610 /* Decode the next character, c, from s, reporting errors in e.
611  *
612  * Since this is a branchless decoder, four bytes will be read from the
613  * buffer regardless of the actual length of the next character. This
614  * means the buffer _must_ have at least three bytes of zero padding
615  * following the end of the data stream.
616  *
617  * Errors are reported in e, which will be non-zero if the parsed
618  * character was somehow invalid: invalid byte sequence, non-canonical
619  * encoding, or a surrogate half.
620  *
621  * The function returns a pointer to the next character. When an error
622  * occurs, this pointer will be a guess that depends on the particular
623  * error, but it will always advance at least one byte.
624  */
625 FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e)
626     -> const char* {
627   constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
628   constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
629   constexpr const int shiftc[] = {0, 18, 12, 6, 0};
630   constexpr const int shifte[] = {0, 6, 4, 2, 0};
631 
632   int len = "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4"
633       [static_cast<unsigned char>(*s) >> 3];
634   // Compute the pointer to the next character early so that the next
635   // iteration can start working on the next character. Neither Clang
636   // nor GCC figure out this reordering on their own.
637   const char* next = s + len + !len;
638 
639   using uchar = unsigned char;
640 
641   // Assume a four-byte character and load four bytes. Unused bits are
642   // shifted out.
643   *c = uint32_t(uchar(s[0]) & masks[len]) << 18;
644   *c |= uint32_t(uchar(s[1]) & 0x3f) << 12;
645   *c |= uint32_t(uchar(s[2]) & 0x3f) << 6;
646   *c |= uint32_t(uchar(s[3]) & 0x3f) << 0;
647   *c >>= shiftc[len];
648 
649   // Accumulate the various error conditions.
650   *e = (*c < mins[len]) << 6;       // non-canonical encoding
651   *e |= ((*c >> 11) == 0x1b) << 7;  // surrogate half?
652   *e |= (*c > 0x10FFFF) << 8;       // out of range?
653   *e |= (uchar(s[1]) & 0xc0) >> 2;
654   *e |= (uchar(s[2]) & 0xc0) >> 4;
655   *e |= uchar(s[3]) >> 6;
656   *e ^= 0x2a;  // top two bits of each tail byte correct?
657   *e >>= shifte[len];
658 
659   return next;
660 }
661 
662 constexpr FMT_INLINE_VARIABLE uint32_t invalid_code_point = ~uint32_t();
663 
664 // Invokes f(cp, sv) for every code point cp in s with sv being the string view
665 // corresponding to the code point. cp is invalid_code_point on error.
666 template <typename F>
for_each_codepoint(string_view s,F f)667 FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) {
668   auto decode = [f](const char* buf_ptr, const char* ptr) {
669     auto cp = uint32_t();
670     auto error = 0;
671     auto end = utf8_decode(buf_ptr, &cp, &error);
672     bool result = f(error ? invalid_code_point : cp,
673                     string_view(ptr, error ? 1 : to_unsigned(end - buf_ptr)));
674     return result ? (error ? buf_ptr + 1 : end) : nullptr;
675   };
676   auto p = s.data();
677   const size_t block_size = 4;  // utf8_decode always reads blocks of 4 chars.
678   if (s.size() >= block_size) {
679     for (auto end = p + s.size() - block_size + 1; p < end;) {
680       p = decode(p, p);
681       if (!p) return;
682     }
683   }
684   if (auto num_chars_left = s.data() + s.size() - p) {
685     char buf[2 * block_size - 1] = {};
686     copy_str<char>(p, p + num_chars_left, buf);
687     const char* buf_ptr = buf;
688     do {
689       auto end = decode(buf_ptr, p);
690       if (!end) return;
691       p += end - buf_ptr;
692       buf_ptr = end;
693     } while (buf_ptr - buf < num_chars_left);
694   }
695 }
696 
697 template <typename Char>
698 inline auto compute_width(basic_string_view<Char> s) -> size_t {
699   return s.size();
700 }
701 
702 // Computes approximate display width of a UTF-8 string.
703 FMT_CONSTEXPR inline auto compute_width(string_view s) -> size_t {
704   size_t num_code_points = 0;
705   // It is not a lambda for compatibility with C++14.
706   struct count_code_points {
707     size_t* count;
708     FMT_CONSTEXPR auto operator()(uint32_t cp, string_view) const -> bool {
709       *count += detail::to_unsigned(
710           1 +
711           (cp >= 0x1100 &&
712            (cp <= 0x115f ||  // Hangul Jamo init. consonants
713             cp == 0x2329 ||  // LEFT-POINTING ANGLE BRACKET
714             cp == 0x232a ||  // RIGHT-POINTING ANGLE BRACKET
715             // CJK ... Yi except IDEOGRAPHIC HALF FILL SPACE:
716             (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) ||
717             (cp >= 0xac00 && cp <= 0xd7a3) ||    // Hangul Syllables
718             (cp >= 0xf900 && cp <= 0xfaff) ||    // CJK Compatibility Ideographs
719             (cp >= 0xfe10 && cp <= 0xfe19) ||    // Vertical Forms
720             (cp >= 0xfe30 && cp <= 0xfe6f) ||    // CJK Compatibility Forms
721             (cp >= 0xff00 && cp <= 0xff60) ||    // Fullwidth Forms
722             (cp >= 0xffe0 && cp <= 0xffe6) ||    // Fullwidth Forms
723             (cp >= 0x20000 && cp <= 0x2fffd) ||  // CJK
724             (cp >= 0x30000 && cp <= 0x3fffd) ||
725             // Miscellaneous Symbols and Pictographs + Emoticons:
726             (cp >= 0x1f300 && cp <= 0x1f64f) ||
727             // Supplemental Symbols and Pictographs:
728             (cp >= 0x1f900 && cp <= 0x1f9ff))));
729       return true;
730     }
731   };
732   // We could avoid branches by using utf8_decode directly.
733   for_each_codepoint(s, count_code_points{&num_code_points});
734   return num_code_points;
735 }
736 
737 inline auto compute_width(basic_string_view<char8_type> s) -> size_t {
738   return compute_width(
739       string_view(reinterpret_cast<const char*>(s.data()), s.size()));
740 }
741 
742 template <typename Char>
743 inline auto code_point_index(basic_string_view<Char> s, size_t n) -> size_t {
744   size_t size = s.size();
745   return n < size ? n : size;
746 }
747 
748 // Calculates the index of the nth code point in a UTF-8 string.
749 inline auto code_point_index(string_view s, size_t n) -> size_t {
750   size_t result = s.size();
751   const char* begin = s.begin();
752   for_each_codepoint(s, [begin, &n, &result](uint32_t, string_view sv) {
753     if (n != 0) {
754       --n;
755       return true;
756     }
757     result = to_unsigned(sv.begin() - begin);
758     return false;
759   });
760   return result;
761 }
762 
763 inline auto code_point_index(basic_string_view<char8_type> s, size_t n)
764     -> size_t {
765   return code_point_index(
766       string_view(reinterpret_cast<const char*>(s.data()), s.size()), n);
767 }
768 
769 template <typename T> struct is_integral : std::is_integral<T> {};
770 template <> struct is_integral<int128_opt> : std::true_type {};
771 template <> struct is_integral<uint128_t> : std::true_type {};
772 
773 template <typename T>
774 using is_signed =
775     std::integral_constant<bool, std::numeric_limits<T>::is_signed ||
776                                      std::is_same<T, int128_opt>::value>;
777 
778 template <typename T>
779 using is_integer =
780     bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value &&
781                   !std::is_same<T, char>::value &&
782                   !std::is_same<T, wchar_t>::value>;
783 
784 #ifndef FMT_USE_FLOAT
785 #  define FMT_USE_FLOAT 1
786 #endif
787 #ifndef FMT_USE_DOUBLE
788 #  define FMT_USE_DOUBLE 1
789 #endif
790 #ifndef FMT_USE_LONG_DOUBLE
791 #  define FMT_USE_LONG_DOUBLE 1
792 #endif
793 
794 #ifndef FMT_USE_FLOAT128
795 #  ifdef __clang__
796 // Clang emulates GCC, so it has to appear early.
797 #    if FMT_HAS_INCLUDE(<quadmath.h>)
798 #      define FMT_USE_FLOAT128 1
799 #    endif
800 #  elif defined(__GNUC__)
801 // GNU C++:
802 #    if defined(_GLIBCXX_USE_FLOAT128) && !defined(__STRICT_ANSI__)
803 #      define FMT_USE_FLOAT128 1
804 #    endif
805 #  endif
806 #  ifndef FMT_USE_FLOAT128
807 #    define FMT_USE_FLOAT128 0
808 #  endif
809 #endif
810 
811 #if FMT_USE_FLOAT128
812 using float128 = __float128;
813 #else
814 using float128 = void;
815 #endif
816 template <typename T> using is_float128 = std::is_same<T, float128>;
817 
818 template <typename T>
819 using is_floating_point =
820     bool_constant<std::is_floating_point<T>::value || is_float128<T>::value>;
821 
822 template <typename T, bool = std::is_floating_point<T>::value>
823 struct is_fast_float : bool_constant<std::numeric_limits<T>::is_iec559 &&
824                                      sizeof(T) <= sizeof(double)> {};
825 template <typename T> struct is_fast_float<T, false> : std::false_type {};
826 
827 template <typename T>
828 using is_double_double = bool_constant<std::numeric_limits<T>::digits == 106>;
829 
830 #ifndef FMT_USE_FULL_CACHE_DRAGONBOX
831 #  define FMT_USE_FULL_CACHE_DRAGONBOX 0
832 #endif
833 
834 template <typename T>
835 template <typename U>
836 void buffer<T>::append(const U* begin, const U* end) {
837   while (begin != end) {
838     auto count = to_unsigned(end - begin);
839     try_reserve(size_ + count);
840     auto free_cap = capacity_ - size_;
841     if (free_cap < count) count = free_cap;
842     std::uninitialized_copy_n(begin, count, ptr_ + size_);
843     size_ += count;
844     begin += count;
845   }
846 }
847 
848 template <typename T, typename Enable = void>
849 struct is_locale : std::false_type {};
850 template <typename T>
851 struct is_locale<T, void_t<decltype(T::classic())>> : std::true_type {};
852 }  // namespace detail
853 
854 FMT_BEGIN_EXPORT
855 
856 // The number of characters to store in the basic_memory_buffer object itself
857 // to avoid dynamic memory allocation.
858 enum { inline_buffer_size = 500 };
859 
860 /**
861   \rst
862   A dynamically growing memory buffer for trivially copyable/constructible types
863   with the first ``SIZE`` elements stored in the object itself.
864 
865   You can use the ``memory_buffer`` type alias for ``char`` instead.
866 
867   **Example**::
868 
869      auto out = fmt::memory_buffer();
870      fmt::format_to(std::back_inserter(out), "The answer is {}.", 42);
871 
872   This will append the following output to the ``out`` object:
873 
874   .. code-block:: none
875 
876      The answer is 42.
877 
878   The output can be converted to an ``std::string`` with ``to_string(out)``.
879   \endrst
880  */
881 template <typename T, size_t SIZE = inline_buffer_size,
882           typename Allocator = std::allocator<T>>
883 class basic_memory_buffer final : public detail::buffer<T> {
884  private:
885   T store_[SIZE];
886 
887   // Don't inherit from Allocator to avoid generating type_info for it.
888   FMT_NO_UNIQUE_ADDRESS Allocator alloc_;
889 
890   // Deallocate memory allocated by the buffer.
891   FMT_CONSTEXPR20 void deallocate() {
892     T* data = this->data();
893     if (data != store_) alloc_.deallocate(data, this->capacity());
894   }
895 
896  protected:
897   FMT_CONSTEXPR20 void grow(size_t size) override {
898     detail::abort_fuzzing_if(size > 5000);
899     const size_t max_size = std::allocator_traits<Allocator>::max_size(alloc_);
900     size_t old_capacity = this->capacity();
901     size_t new_capacity = old_capacity + old_capacity / 2;
902     if (size > new_capacity)
903       new_capacity = size;
904     else if (new_capacity > max_size)
905       new_capacity = size > max_size ? size : max_size;
906     T* old_data = this->data();
907     T* new_data =
908         std::allocator_traits<Allocator>::allocate(alloc_, new_capacity);
909     // Suppress a bogus -Wstringop-overflow in gcc 13.1 (#3481).
910     detail::assume(this->size() <= new_capacity);
911     // The following code doesn't throw, so the raw pointer above doesn't leak.
912     std::uninitialized_copy_n(old_data, this->size(), new_data);
913     this->set(new_data, new_capacity);
914     // deallocate must not throw according to the standard, but even if it does,
915     // the buffer already uses the new storage and will deallocate it in
916     // destructor.
917     if (old_data != store_) alloc_.deallocate(old_data, old_capacity);
918   }
919 
920  public:
921   using value_type = T;
922   using const_reference = const T&;
923 
924   FMT_CONSTEXPR20 explicit basic_memory_buffer(
925       const Allocator& alloc = Allocator())
926       : alloc_(alloc) {
927     this->set(store_, SIZE);
928     if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T());
929   }
930   FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); }
931 
932  private:
933   // Move data from other to this buffer.
934   FMT_CONSTEXPR20 void move(basic_memory_buffer& other) {
935     alloc_ = std::move(other.alloc_);
936     T* data = other.data();
937     size_t size = other.size(), capacity = other.capacity();
938     if (data == other.store_) {
939       this->set(store_, capacity);
940       detail::copy_str<T>(other.store_, other.store_ + size, store_);
941     } else {
942       this->set(data, capacity);
943       // Set pointer to the inline array so that delete is not called
944       // when deallocating.
945       other.set(other.store_, 0);
946       other.clear();
947     }
948     this->resize(size);
949   }
950 
951  public:
952   /**
953     \rst
954     Constructs a :class:`fmt::basic_memory_buffer` object moving the content
955     of the other object to it.
956     \endrst
957    */
958   FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other) noexcept {
959     move(other);
960   }
961 
962   /**
963     \rst
964     Moves the content of the other ``basic_memory_buffer`` object to this one.
965     \endrst
966    */
967   auto operator=(basic_memory_buffer&& other) noexcept -> basic_memory_buffer& {
968     FMT_ASSERT(this != &other, "");
969     deallocate();
970     move(other);
971     return *this;
972   }
973 
974   // Returns a copy of the allocator associated with this buffer.
975   auto get_allocator() const -> Allocator { return alloc_; }
976 
977   /**
978     Resizes the buffer to contain *count* elements. If T is a POD type new
979     elements may not be initialized.
980    */
981   FMT_CONSTEXPR20 void resize(size_t count) { this->try_resize(count); }
982 
983   /** Increases the buffer capacity to *new_capacity*. */
984   void reserve(size_t new_capacity) { this->try_reserve(new_capacity); }
985 
986   using detail::buffer<T>::append;
987   template <typename ContiguousRange>
988   void append(const ContiguousRange& range) {
989     append(range.data(), range.data() + range.size());
990   }
991 };
992 
993 using memory_buffer = basic_memory_buffer<char>;
994 
995 template <typename T, size_t SIZE, typename Allocator>
996 struct is_contiguous<basic_memory_buffer<T, SIZE, Allocator>> : std::true_type {
997 };
998 
999 FMT_END_EXPORT
1000 namespace detail {
1001 FMT_API auto write_console(int fd, string_view text) -> bool;
1002 FMT_API void print(std::FILE*, string_view);
1003 }  // namespace detail
1004 
1005 FMT_BEGIN_EXPORT
1006 
1007 // Suppress a misleading warning in older versions of clang.
1008 #if FMT_CLANG_VERSION
1009 #  pragma clang diagnostic ignored "-Wweak-vtables"
1010 #endif
1011 
1012 /** An error reported from a formatting function. */
1013 class FMT_SO_VISIBILITY("default") format_error : public std::runtime_error {
1014  public:
1015   using std::runtime_error::runtime_error;
1016 };
1017 
1018 namespace detail_exported {
1019 #if FMT_USE_NONTYPE_TEMPLATE_ARGS
1020 template <typename Char, size_t N> struct fixed_string {
1021   constexpr fixed_string(const Char (&str)[N]) {
1022     detail::copy_str<Char, const Char*, Char*>(static_cast<const Char*>(str),
1023                                                str + N, data);
1024   }
1025   Char data[N] = {};
1026 };
1027 #endif
1028 
1029 // Converts a compile-time string to basic_string_view.
1030 template <typename Char, size_t N>
1031 constexpr auto compile_string_to_view(const Char (&s)[N])
1032     -> basic_string_view<Char> {
1033   // Remove trailing NUL character if needed. Won't be present if this is used
1034   // with a raw character array (i.e. not defined as a string).
1035   return {s, N - (std::char_traits<Char>::to_int_type(s[N - 1]) == 0 ? 1 : 0)};
1036 }
1037 template <typename Char>
1038 constexpr auto compile_string_to_view(detail::std_string_view<Char> s)
1039     -> basic_string_view<Char> {
1040   return {s.data(), s.size()};
1041 }
1042 }  // namespace detail_exported
1043 
1044 class loc_value {
1045  private:
1046   basic_format_arg<format_context> value_;
1047 
1048  public:
1049   template <typename T, FMT_ENABLE_IF(!detail::is_float128<T>::value)>
1050   loc_value(T value) : value_(detail::make_arg<format_context>(value)) {}
1051 
1052   template <typename T, FMT_ENABLE_IF(detail::is_float128<T>::value)>
1053   loc_value(T) {}
1054 
1055   template <typename Visitor> auto visit(Visitor&& vis) -> decltype(vis(0)) {
1056     return visit_format_arg(vis, value_);
1057   }
1058 };
1059 
1060 // A locale facet that formats values in UTF-8.
1061 // It is parameterized on the locale to avoid the heavy <locale> include.
1062 template <typename Locale> class format_facet : public Locale::facet {
1063  private:
1064   std::string separator_;
1065   std::string grouping_;
1066   std::string decimal_point_;
1067 
1068  protected:
1069   virtual auto do_put(appender out, loc_value val,
1070                       const format_specs<>& specs) const -> bool;
1071 
1072  public:
1073   static FMT_API typename Locale::id id;
1074 
1075   explicit format_facet(Locale& loc);
1076   explicit format_facet(string_view sep = "",
1077                         std::initializer_list<unsigned char> g = {3},
1078                         std::string decimal_point = ".")
1079       : separator_(sep.data(), sep.size()),
1080         grouping_(g.begin(), g.end()),
1081         decimal_point_(decimal_point) {}
1082 
1083   auto put(appender out, loc_value val, const format_specs<>& specs) const
1084       -> bool {
1085     return do_put(out, val, specs);
1086   }
1087 };
1088 
1089 namespace detail {
1090 
1091 // Returns true if value is negative, false otherwise.
1092 // Same as `value < 0` but doesn't produce warnings if T is an unsigned type.
1093 template <typename T, FMT_ENABLE_IF(is_signed<T>::value)>
1094 constexpr auto is_negative(T value) -> bool {
1095   return value < 0;
1096 }
1097 template <typename T, FMT_ENABLE_IF(!is_signed<T>::value)>
1098 constexpr auto is_negative(T) -> bool {
1099   return false;
1100 }
1101 
1102 template <typename T>
1103 FMT_CONSTEXPR auto is_supported_floating_point(T) -> bool {
1104   if (std::is_same<T, float>()) return FMT_USE_FLOAT;
1105   if (std::is_same<T, double>()) return FMT_USE_DOUBLE;
1106   if (std::is_same<T, long double>()) return FMT_USE_LONG_DOUBLE;
1107   return true;
1108 }
1109 
1110 // Smallest of uint32_t, uint64_t, uint128_t that is large enough to
1111 // represent all values of an integral type T.
1112 template <typename T>
1113 using uint32_or_64_or_128_t =
1114     conditional_t<num_bits<T>() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS,
1115                   uint32_t,
1116                   conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>;
1117 template <typename T>
1118 using uint64_or_128_t = conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>;
1119 
1120 #define FMT_POWERS_OF_10(factor)                                  \
1121   factor * 10, (factor) * 100, (factor) * 1000, (factor) * 10000, \
1122       (factor) * 100000, (factor) * 1000000, (factor) * 10000000, \
1123       (factor) * 100000000, (factor) * 1000000000
1124 
1125 // Converts value in the range [0, 100) to a string.
1126 constexpr auto digits2(size_t value) -> const char* {
1127   // GCC generates slightly better code when value is pointer-size.
1128   return &"0001020304050607080910111213141516171819"
1129          "2021222324252627282930313233343536373839"
1130          "4041424344454647484950515253545556575859"
1131          "6061626364656667686970717273747576777879"
1132          "8081828384858687888990919293949596979899"[value * 2];
1133 }
1134 
1135 // Sign is a template parameter to workaround a bug in gcc 4.8.
1136 template <typename Char, typename Sign> constexpr auto sign(Sign s) -> Char {
1137 #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604
1138   static_assert(std::is_same<Sign, sign_t>::value, "");
1139 #endif
1140   return static_cast<Char>("\0-+ "[s]);
1141 }
1142 
1143 template <typename T> FMT_CONSTEXPR auto count_digits_fallback(T n) -> int {
1144   int count = 1;
1145   for (;;) {
1146     // Integer division is slow so do it for a group of four digits instead
1147     // of for every digit. The idea comes from the talk by Alexandrescu
1148     // "Three Optimization Tips for C++". See speed-test for a comparison.
1149     if (n < 10) return count;
1150     if (n < 100) return count + 1;
1151     if (n < 1000) return count + 2;
1152     if (n < 10000) return count + 3;
1153     n /= 10000u;
1154     count += 4;
1155   }
1156 }
1157 #if FMT_USE_INT128
1158 FMT_CONSTEXPR inline auto count_digits(uint128_opt n) -> int {
1159   return count_digits_fallback(n);
1160 }
1161 #endif
1162 
1163 #ifdef FMT_BUILTIN_CLZLL
1164 // It is a separate function rather than a part of count_digits to workaround
1165 // the lack of static constexpr in constexpr functions.
1166 inline auto do_count_digits(uint64_t n) -> int {
1167   // This has comparable performance to the version by Kendall Willets
1168   // (https://github.com/fmtlib/format-benchmark/blob/master/digits10)
1169   // but uses smaller tables.
1170   // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)).
1171   static constexpr uint8_t bsr2log10[] = {
1172       1,  1,  1,  2,  2,  2,  3,  3,  3,  4,  4,  4,  4,  5,  5,  5,
1173       6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  9,  9,  9,  10, 10, 10,
1174       10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
1175       15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20};
1176   auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63];
1177   static constexpr const uint64_t zero_or_powers_of_10[] = {
1178       0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL),
1179       10000000000000000000ULL};
1180   return t - (n < zero_or_powers_of_10[t]);
1181 }
1182 #endif
1183 
1184 // Returns the number of decimal digits in n. Leading zeros are not counted
1185 // except for n == 0 in which case count_digits returns 1.
1186 FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int {
1187 #ifdef FMT_BUILTIN_CLZLL
1188   if (!is_constant_evaluated()) {
1189     return do_count_digits(n);
1190   }
1191 #endif
1192   return count_digits_fallback(n);
1193 }
1194 
1195 // Counts the number of digits in n. BITS = log2(radix).
1196 template <int BITS, typename UInt>
1197 FMT_CONSTEXPR auto count_digits(UInt n) -> int {
1198 #ifdef FMT_BUILTIN_CLZ
1199   if (!is_constant_evaluated() && num_bits<UInt>() == 32)
1200     return (FMT_BUILTIN_CLZ(static_cast<uint32_t>(n) | 1) ^ 31) / BITS + 1;
1201 #endif
1202   // Lambda avoids unreachable code warnings from NVHPC.
1203   return [](UInt m) {
1204     int num_digits = 0;
1205     do {
1206       ++num_digits;
1207     } while ((m >>= BITS) != 0);
1208     return num_digits;
1209   }(n);
1210 }
1211 
1212 #ifdef FMT_BUILTIN_CLZ
1213 // It is a separate function rather than a part of count_digits to workaround
1214 // the lack of static constexpr in constexpr functions.
1215 FMT_INLINE auto do_count_digits(uint32_t n) -> int {
1216 // An optimization by Kendall Willets from https://bit.ly/3uOIQrB.
1217 // This increments the upper 32 bits (log10(T) - 1) when >= T is added.
1218 #  define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T)
1219   static constexpr uint64_t table[] = {
1220       FMT_INC(0),          FMT_INC(0),          FMT_INC(0),           // 8
1221       FMT_INC(10),         FMT_INC(10),         FMT_INC(10),          // 64
1222       FMT_INC(100),        FMT_INC(100),        FMT_INC(100),         // 512
1223       FMT_INC(1000),       FMT_INC(1000),       FMT_INC(1000),        // 4096
1224       FMT_INC(10000),      FMT_INC(10000),      FMT_INC(10000),       // 32k
1225       FMT_INC(100000),     FMT_INC(100000),     FMT_INC(100000),      // 256k
1226       FMT_INC(1000000),    FMT_INC(1000000),    FMT_INC(1000000),     // 2048k
1227       FMT_INC(10000000),   FMT_INC(10000000),   FMT_INC(10000000),    // 16M
1228       FMT_INC(100000000),  FMT_INC(100000000),  FMT_INC(100000000),   // 128M
1229       FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000),  // 1024M
1230       FMT_INC(1000000000), FMT_INC(1000000000)                        // 4B
1231   };
1232   auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31];
1233   return static_cast<int>((n + inc) >> 32);
1234 }
1235 #endif
1236 
1237 // Optional version of count_digits for better performance on 32-bit platforms.
1238 FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int {
1239 #ifdef FMT_BUILTIN_CLZ
1240   if (!is_constant_evaluated()) {
1241     return do_count_digits(n);
1242   }
1243 #endif
1244   return count_digits_fallback(n);
1245 }
1246 
1247 template <typename Int> constexpr auto digits10() noexcept -> int {
1248   return std::numeric_limits<Int>::digits10;
1249 }
1250 template <> constexpr auto digits10<int128_opt>() noexcept -> int { return 38; }
1251 template <> constexpr auto digits10<uint128_t>() noexcept -> int { return 38; }
1252 
1253 template <typename Char> struct thousands_sep_result {
1254   std::string grouping;
1255   Char thousands_sep;
1256 };
1257 
1258 template <typename Char>
1259 FMT_API auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result<Char>;
1260 template <typename Char>
1261 inline auto thousands_sep(locale_ref loc) -> thousands_sep_result<Char> {
1262   auto result = thousands_sep_impl<char>(loc);
1263   return {result.grouping, Char(result.thousands_sep)};
1264 }
1265 template <>
1266 inline auto thousands_sep(locale_ref loc) -> thousands_sep_result<wchar_t> {
1267   return thousands_sep_impl<wchar_t>(loc);
1268 }
1269 
1270 template <typename Char>
1271 FMT_API auto decimal_point_impl(locale_ref loc) -> Char;
1272 template <typename Char> inline auto decimal_point(locale_ref loc) -> Char {
1273   return Char(decimal_point_impl<char>(loc));
1274 }
1275 template <> inline auto decimal_point(locale_ref loc) -> wchar_t {
1276   return decimal_point_impl<wchar_t>(loc);
1277 }
1278 
1279 // Compares two characters for equality.
1280 template <typename Char> auto equal2(const Char* lhs, const char* rhs) -> bool {
1281   return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]);
1282 }
1283 inline auto equal2(const char* lhs, const char* rhs) -> bool {
1284   return memcmp(lhs, rhs, 2) == 0;
1285 }
1286 
1287 // Copies two characters from src to dst.
1288 template <typename Char>
1289 FMT_CONSTEXPR20 FMT_INLINE void copy2(Char* dst, const char* src) {
1290   if (!is_constant_evaluated() && sizeof(Char) == sizeof(char)) {
1291     memcpy(dst, src, 2);
1292     return;
1293   }
1294   *dst++ = static_cast<Char>(*src++);
1295   *dst = static_cast<Char>(*src);
1296 }
1297 
1298 template <typename Iterator> struct format_decimal_result {
1299   Iterator begin;
1300   Iterator end;
1301 };
1302 
1303 // Formats a decimal unsigned integer value writing into out pointing to a
1304 // buffer of specified size. The caller must ensure that the buffer is large
1305 // enough.
1306 template <typename Char, typename UInt>
1307 FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size)
1308     -> format_decimal_result<Char*> {
1309   FMT_ASSERT(size >= count_digits(value), "invalid digit count");
1310   out += size;
1311   Char* end = out;
1312   while (value >= 100) {
1313     // Integer division is slow so do it for a group of two digits instead
1314     // of for every digit. The idea comes from the talk by Alexandrescu
1315     // "Three Optimization Tips for C++". See speed-test for a comparison.
1316     out -= 2;
1317     copy2(out, digits2(static_cast<size_t>(value % 100)));
1318     value /= 100;
1319   }
1320   if (value < 10) {
1321     *--out = static_cast<Char>('0' + value);
1322     return {out, end};
1323   }
1324   out -= 2;
1325   copy2(out, digits2(static_cast<size_t>(value)));
1326   return {out, end};
1327 }
1328 
1329 template <typename Char, typename UInt, typename Iterator,
1330           FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<Iterator>>::value)>
1331 FMT_CONSTEXPR inline auto format_decimal(Iterator out, UInt value, int size)
1332     -> format_decimal_result<Iterator> {
1333   // Buffer is large enough to hold all digits (digits10 + 1).
1334   Char buffer[digits10<UInt>() + 1] = {};
1335   auto end = format_decimal(buffer, value, size).end;
1336   return {out, detail::copy_str_noinline<Char>(buffer, end, out)};
1337 }
1338 
1339 template <unsigned BASE_BITS, typename Char, typename UInt>
1340 FMT_CONSTEXPR auto format_uint(Char* buffer, UInt value, int num_digits,
1341                                bool upper = false) -> Char* {
1342   buffer += num_digits;
1343   Char* end = buffer;
1344   do {
1345     const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef";
1346     unsigned digit = static_cast<unsigned>(value & ((1 << BASE_BITS) - 1));
1347     *--buffer = static_cast<Char>(BASE_BITS < 4 ? static_cast<char>('0' + digit)
1348                                                 : digits[digit]);
1349   } while ((value >>= BASE_BITS) != 0);
1350   return end;
1351 }
1352 
1353 template <unsigned BASE_BITS, typename Char, typename It, typename UInt>
1354 FMT_CONSTEXPR inline auto format_uint(It out, UInt value, int num_digits,
1355                                       bool upper = false) -> It {
1356   if (auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
1357     format_uint<BASE_BITS>(ptr, value, num_digits, upper);
1358     return out;
1359   }
1360   // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1).
1361   char buffer[num_bits<UInt>() / BASE_BITS + 1] = {};
1362   format_uint<BASE_BITS>(buffer, value, num_digits, upper);
1363   return detail::copy_str_noinline<Char>(buffer, buffer + num_digits, out);
1364 }
1365 
1366 // A converter from UTF-8 to UTF-16.
1367 class utf8_to_utf16 {
1368  private:
1369   basic_memory_buffer<wchar_t> buffer_;
1370 
1371  public:
1372   FMT_API explicit utf8_to_utf16(string_view s);
1373   operator basic_string_view<wchar_t>() const { return {&buffer_[0], size()}; }
1374   auto size() const -> size_t { return buffer_.size() - 1; }
1375   auto c_str() const -> const wchar_t* { return &buffer_[0]; }
1376   auto str() const -> std::wstring { return {&buffer_[0], size()}; }
1377 };
1378 
1379 enum class to_utf8_error_policy { abort, replace };
1380 
1381 // A converter from UTF-16/UTF-32 (host endian) to UTF-8.
1382 template <typename WChar, typename Buffer = memory_buffer> class to_utf8 {
1383  private:
1384   Buffer buffer_;
1385 
1386  public:
1387   to_utf8() {}
1388   explicit to_utf8(basic_string_view<WChar> s,
1389                    to_utf8_error_policy policy = to_utf8_error_policy::abort) {
1390     static_assert(sizeof(WChar) == 2 || sizeof(WChar) == 4,
1391                   "Expect utf16 or utf32");
1392     if (!convert(s, policy))
1393       FMT_THROW(std::runtime_error(sizeof(WChar) == 2 ? "invalid utf16"
1394                                                       : "invalid utf32"));
1395   }
1396   operator string_view() const { return string_view(&buffer_[0], size()); }
1397   auto size() const -> size_t { return buffer_.size() - 1; }
1398   auto c_str() const -> const char* { return &buffer_[0]; }
1399   auto str() const -> std::string { return std::string(&buffer_[0], size()); }
1400 
1401   // Performs conversion returning a bool instead of throwing exception on
1402   // conversion error. This method may still throw in case of memory allocation
1403   // error.
1404   auto convert(basic_string_view<WChar> s,
1405                to_utf8_error_policy policy = to_utf8_error_policy::abort)
1406       -> bool {
1407     if (!convert(buffer_, s, policy)) return false;
1408     buffer_.push_back(0);
1409     return true;
1410   }
1411   static auto convert(Buffer& buf, basic_string_view<WChar> s,
1412                       to_utf8_error_policy policy = to_utf8_error_policy::abort)
1413       -> bool {
1414     for (auto p = s.begin(); p != s.end(); ++p) {
1415       uint32_t c = static_cast<uint32_t>(*p);
1416       if (sizeof(WChar) == 2 && c >= 0xd800 && c <= 0xdfff) {
1417         // Handle a surrogate pair.
1418         ++p;
1419         if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) {
1420           if (policy == to_utf8_error_policy::abort) return false;
1421           buf.append(string_view("\xEF\xBF\xBD"));
1422           --p;
1423         } else {
1424           c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;
1425         }
1426       } else if (c < 0x80) {
1427         buf.push_back(static_cast<char>(c));
1428       } else if (c < 0x800) {
1429         buf.push_back(static_cast<char>(0xc0 | (c >> 6)));
1430         buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
1431       } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
1432         buf.push_back(static_cast<char>(0xe0 | (c >> 12)));
1433         buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
1434         buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
1435       } else if (c >= 0x10000 && c <= 0x10ffff) {
1436         buf.push_back(static_cast<char>(0xf0 | (c >> 18)));
1437         buf.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
1438         buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
1439         buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
1440       } else {
1441         return false;
1442       }
1443     }
1444     return true;
1445   }
1446 };
1447 
1448 // Computes 128-bit result of multiplication of two 64-bit unsigned integers.
1449 inline auto umul128(uint64_t x, uint64_t y) noexcept -> uint128_fallback {
1450 #if FMT_USE_INT128
1451   auto p = static_cast<uint128_opt>(x) * static_cast<uint128_opt>(y);
1452   return {static_cast<uint64_t>(p >> 64), static_cast<uint64_t>(p)};
1453 #elif defined(_MSC_VER) && defined(_M_X64)
1454   auto hi = uint64_t();
1455   auto lo = _umul128(x, y, &hi);
1456   return {hi, lo};
1457 #else
1458   const uint64_t mask = static_cast<uint64_t>(max_value<uint32_t>());
1459 
1460   uint64_t a = x >> 32;
1461   uint64_t b = x & mask;
1462   uint64_t c = y >> 32;
1463   uint64_t d = y & mask;
1464 
1465   uint64_t ac = a * c;
1466   uint64_t bc = b * c;
1467   uint64_t ad = a * d;
1468   uint64_t bd = b * d;
1469 
1470   uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask);
1471 
1472   return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32),
1473           (intermediate << 32) + (bd & mask)};
1474 #endif
1475 }
1476 
1477 namespace dragonbox {
1478 // Computes floor(log10(pow(2, e))) for e in [-2620, 2620] using the method from
1479 // https://fmt.dev/papers/Dragonbox.pdf#page=28, section 6.1.
1480 inline auto floor_log10_pow2(int e) noexcept -> int {
1481   FMT_ASSERT(e <= 2620 && e >= -2620, "too large exponent");
1482   static_assert((-1 >> 1) == -1, "right shift is not arithmetic");
1483   return (e * 315653) >> 20;
1484 }
1485 
1486 inline auto floor_log2_pow10(int e) noexcept -> int {
1487   FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent");
1488   return (e * 1741647) >> 19;
1489 }
1490 
1491 // Computes upper 64 bits of multiplication of two 64-bit unsigned integers.
1492 inline auto umul128_upper64(uint64_t x, uint64_t y) noexcept -> uint64_t {
1493 #if FMT_USE_INT128
1494   auto p = static_cast<uint128_opt>(x) * static_cast<uint128_opt>(y);
1495   return static_cast<uint64_t>(p >> 64);
1496 #elif defined(_MSC_VER) && defined(_M_X64)
1497   return __umulh(x, y);
1498 #else
1499   return umul128(x, y).high();
1500 #endif
1501 }
1502 
1503 // Computes upper 128 bits of multiplication of a 64-bit unsigned integer and a
1504 // 128-bit unsigned integer.
1505 inline auto umul192_upper128(uint64_t x, uint128_fallback y) noexcept
1506     -> uint128_fallback {
1507   uint128_fallback r = umul128(x, y.high());
1508   r += umul128_upper64(x, y.low());
1509   return r;
1510 }
1511 
1512 FMT_API auto get_cached_power(int k) noexcept -> uint128_fallback;
1513 
1514 // Type-specific information that Dragonbox uses.
1515 template <typename T, typename Enable = void> struct float_info;
1516 
1517 template <> struct float_info<float> {
1518   using carrier_uint = uint32_t;
1519   static const int exponent_bits = 8;
1520   static const int kappa = 1;
1521   static const int big_divisor = 100;
1522   static const int small_divisor = 10;
1523   static const int min_k = -31;
1524   static const int max_k = 46;
1525   static const int shorter_interval_tie_lower_threshold = -35;
1526   static const int shorter_interval_tie_upper_threshold = -35;
1527 };
1528 
1529 template <> struct float_info<double> {
1530   using carrier_uint = uint64_t;
1531   static const int exponent_bits = 11;
1532   static const int kappa = 2;
1533   static const int big_divisor = 1000;
1534   static const int small_divisor = 100;
1535   static const int min_k = -292;
1536   static const int max_k = 341;
1537   static const int shorter_interval_tie_lower_threshold = -77;
1538   static const int shorter_interval_tie_upper_threshold = -77;
1539 };
1540 
1541 // An 80- or 128-bit floating point number.
1542 template <typename T>
1543 struct float_info<T, enable_if_t<std::numeric_limits<T>::digits == 64 ||
1544                                  std::numeric_limits<T>::digits == 113 ||
1545                                  is_float128<T>::value>> {
1546   using carrier_uint = detail::uint128_t;
1547   static const int exponent_bits = 15;
1548 };
1549 
1550 // A double-double floating point number.
1551 template <typename T>
1552 struct float_info<T, enable_if_t<is_double_double<T>::value>> {
1553   using carrier_uint = detail::uint128_t;
1554 };
1555 
1556 template <typename T> struct decimal_fp {
1557   using significand_type = typename float_info<T>::carrier_uint;
1558   significand_type significand;
1559   int exponent;
1560 };
1561 
1562 template <typename T> FMT_API auto to_decimal(T x) noexcept -> decimal_fp<T>;
1563 }  // namespace dragonbox
1564 
1565 // Returns true iff Float has the implicit bit which is not stored.
1566 template <typename Float> constexpr auto has_implicit_bit() -> bool {
1567   // An 80-bit FP number has a 64-bit significand an no implicit bit.
1568   return std::numeric_limits<Float>::digits != 64;
1569 }
1570 
1571 // Returns the number of significand bits stored in Float. The implicit bit is
1572 // not counted since it is not stored.
1573 template <typename Float> constexpr auto num_significand_bits() -> int {
1574   // std::numeric_limits may not support __float128.
1575   return is_float128<Float>() ? 112
1576                               : (std::numeric_limits<Float>::digits -
1577                                  (has_implicit_bit<Float>() ? 1 : 0));
1578 }
1579 
1580 template <typename Float>
1581 constexpr auto exponent_mask() ->
1582     typename dragonbox::float_info<Float>::carrier_uint {
1583   using float_uint = typename dragonbox::float_info<Float>::carrier_uint;
1584   return ((float_uint(1) << dragonbox::float_info<Float>::exponent_bits) - 1)
1585          << num_significand_bits<Float>();
1586 }
1587 template <typename Float> constexpr auto exponent_bias() -> int {
1588   // std::numeric_limits may not support __float128.
1589   return is_float128<Float>() ? 16383
1590                               : std::numeric_limits<Float>::max_exponent - 1;
1591 }
1592 
1593 // Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
1594 template <typename Char, typename It>
1595 FMT_CONSTEXPR auto write_exponent(int exp, It it) -> It {
1596   FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range");
1597   if (exp < 0) {
1598     *it++ = static_cast<Char>('-');
1599     exp = -exp;
1600   } else {
1601     *it++ = static_cast<Char>('+');
1602   }
1603   if (exp >= 100) {
1604     const char* top = digits2(to_unsigned(exp / 100));
1605     if (exp >= 1000) *it++ = static_cast<Char>(top[0]);
1606     *it++ = static_cast<Char>(top[1]);
1607     exp %= 100;
1608   }
1609   const char* d = digits2(to_unsigned(exp));
1610   *it++ = static_cast<Char>(d[0]);
1611   *it++ = static_cast<Char>(d[1]);
1612   return it;
1613 }
1614 
1615 // A floating-point number f * pow(2, e) where F is an unsigned type.
1616 template <typename F> struct basic_fp {
1617   F f;
1618   int e;
1619 
1620   static constexpr const int num_significand_bits =
1621       static_cast<int>(sizeof(F) * num_bits<unsigned char>());
1622 
1623   constexpr basic_fp() : f(0), e(0) {}
1624   constexpr basic_fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {}
1625 
1626   // Constructs fp from an IEEE754 floating-point number.
1627   template <typename Float> FMT_CONSTEXPR basic_fp(Float n) { assign(n); }
1628 
1629   // Assigns n to this and return true iff predecessor is closer than successor.
1630   template <typename Float, FMT_ENABLE_IF(!is_double_double<Float>::value)>
1631   FMT_CONSTEXPR auto assign(Float n) -> bool {
1632     static_assert(std::numeric_limits<Float>::digits <= 113, "unsupported FP");
1633     // Assume Float is in the format [sign][exponent][significand].
1634     using carrier_uint = typename dragonbox::float_info<Float>::carrier_uint;
1635     const auto num_float_significand_bits =
1636         detail::num_significand_bits<Float>();
1637     const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
1638     const auto significand_mask = implicit_bit - 1;
1639     auto u = bit_cast<carrier_uint>(n);
1640     f = static_cast<F>(u & significand_mask);
1641     auto biased_e = static_cast<int>((u & exponent_mask<Float>()) >>
1642                                      num_float_significand_bits);
1643     // The predecessor is closer if n is a normalized power of 2 (f == 0)
1644     // other than the smallest normalized number (biased_e > 1).
1645     auto is_predecessor_closer = f == 0 && biased_e > 1;
1646     if (biased_e == 0)
1647       biased_e = 1;  // Subnormals use biased exponent 1 (min exponent).
1648     else if (has_implicit_bit<Float>())
1649       f += static_cast<F>(implicit_bit);
1650     e = biased_e - exponent_bias<Float>() - num_float_significand_bits;
1651     if (!has_implicit_bit<Float>()) ++e;
1652     return is_predecessor_closer;
1653   }
1654 
1655   template <typename Float, FMT_ENABLE_IF(is_double_double<Float>::value)>
1656   FMT_CONSTEXPR auto assign(Float n) -> bool {
1657     static_assert(std::numeric_limits<double>::is_iec559, "unsupported FP");
1658     return assign(static_cast<double>(n));
1659   }
1660 };
1661 
1662 using fp = basic_fp<unsigned long long>;
1663 
1664 // Normalizes the value converted from double and multiplied by (1 << SHIFT).
1665 template <int SHIFT = 0, typename F>
1666 FMT_CONSTEXPR auto normalize(basic_fp<F> value) -> basic_fp<F> {
1667   // Handle subnormals.
1668   const auto implicit_bit = F(1) << num_significand_bits<double>();
1669   const auto shifted_implicit_bit = implicit_bit << SHIFT;
1670   while ((value.f & shifted_implicit_bit) == 0) {
1671     value.f <<= 1;
1672     --value.e;
1673   }
1674   // Subtract 1 to account for hidden bit.
1675   const auto offset = basic_fp<F>::num_significand_bits -
1676                       num_significand_bits<double>() - SHIFT - 1;
1677   value.f <<= offset;
1678   value.e -= offset;
1679   return value;
1680 }
1681 
1682 // Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking.
1683 FMT_CONSTEXPR inline auto multiply(uint64_t lhs, uint64_t rhs) -> uint64_t {
1684 #if FMT_USE_INT128
1685   auto product = static_cast<__uint128_t>(lhs) * rhs;
1686   auto f = static_cast<uint64_t>(product >> 64);
1687   return (static_cast<uint64_t>(product) & (1ULL << 63)) != 0 ? f + 1 : f;
1688 #else
1689   // Multiply 32-bit parts of significands.
1690   uint64_t mask = (1ULL << 32) - 1;
1691   uint64_t a = lhs >> 32, b = lhs & mask;
1692   uint64_t c = rhs >> 32, d = rhs & mask;
1693   uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
1694   // Compute mid 64-bit of result and round.
1695   uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
1696   return ac + (ad >> 32) + (bc >> 32) + (mid >> 32);
1697 #endif
1698 }
1699 
1700 FMT_CONSTEXPR inline auto operator*(fp x, fp y) -> fp {
1701   return {multiply(x.f, y.f), x.e + y.e + 64};
1702 }
1703 
1704 template <typename T, bool doublish = num_bits<T>() == num_bits<double>()>
1705 using convert_float_result =
1706     conditional_t<std::is_same<T, float>::value || doublish, double, T>;
1707 
1708 template <typename T>
1709 constexpr auto convert_float(T value) -> convert_float_result<T> {
1710   return static_cast<convert_float_result<T>>(value);
1711 }
1712 
1713 template <typename OutputIt, typename Char>
1714 FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n,
1715                                      const fill_t<Char>& fill) -> OutputIt {
1716   auto fill_size = fill.size();
1717   if (fill_size == 1) return detail::fill_n(it, n, fill[0]);
1718   auto data = fill.data();
1719   for (size_t i = 0; i < n; ++i)
1720     it = copy_str<Char>(data, data + fill_size, it);
1721   return it;
1722 }
1723 
1724 // Writes the output of f, padded according to format specifications in specs.
1725 // size: output size in code units.
1726 // width: output display width in (terminal) column positions.
1727 template <align::type align = align::left, typename OutputIt, typename Char,
1728           typename F>
1729 FMT_CONSTEXPR auto write_padded(OutputIt out, const format_specs<Char>& specs,
1730                                 size_t size, size_t width, F&& f) -> OutputIt {
1731   static_assert(align == align::left || align == align::right, "");
1732   unsigned spec_width = to_unsigned(specs.width);
1733   size_t padding = spec_width > width ? spec_width - width : 0;
1734   // Shifts are encoded as string literals because static constexpr is not
1735   // supported in constexpr functions.
1736   auto* shifts = align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01";
1737   size_t left_padding = padding >> shifts[specs.align];
1738   size_t right_padding = padding - left_padding;
1739   auto it = reserve(out, size + padding * specs.fill.size());
1740   if (left_padding != 0) it = fill(it, left_padding, specs.fill);
1741   it = f(it);
1742   if (right_padding != 0) it = fill(it, right_padding, specs.fill);
1743   return base_iterator(out, it);
1744 }
1745 
1746 template <align::type align = align::left, typename OutputIt, typename Char,
1747           typename F>
1748 constexpr auto write_padded(OutputIt out, const format_specs<Char>& specs,
1749                             size_t size, F&& f) -> OutputIt {
1750   return write_padded<align>(out, specs, size, size, f);
1751 }
1752 
1753 template <align::type align = align::left, typename Char, typename OutputIt>
1754 FMT_CONSTEXPR auto write_bytes(OutputIt out, string_view bytes,
1755                                const format_specs<Char>& specs) -> OutputIt {
1756   return write_padded<align>(
1757       out, specs, bytes.size(), [bytes](reserve_iterator<OutputIt> it) {
1758         const char* data = bytes.data();
1759         return copy_str<Char>(data, data + bytes.size(), it);
1760       });
1761 }
1762 
1763 template <typename Char, typename OutputIt, typename UIntPtr>
1764 auto write_ptr(OutputIt out, UIntPtr value, const format_specs<Char>* specs)
1765     -> OutputIt {
1766   int num_digits = count_digits<4>(value);
1767   auto size = to_unsigned(num_digits) + size_t(2);
1768   auto write = [=](reserve_iterator<OutputIt> it) {
1769     *it++ = static_cast<Char>('0');
1770     *it++ = static_cast<Char>('x');
1771     return format_uint<4, Char>(it, value, num_digits);
1772   };
1773   return specs ? write_padded<align::right>(out, *specs, size, write)
1774                : base_iterator(out, write(reserve(out, size)));
1775 }
1776 
1777 // Returns true iff the code point cp is printable.
1778 FMT_API auto is_printable(uint32_t cp) -> bool;
1779 
1780 inline auto needs_escape(uint32_t cp) -> bool {
1781   return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' ||
1782          !is_printable(cp);
1783 }
1784 
1785 template <typename Char> struct find_escape_result {
1786   const Char* begin;
1787   const Char* end;
1788   uint32_t cp;
1789 };
1790 
1791 template <typename Char>
1792 using make_unsigned_char =
1793     typename conditional_t<std::is_integral<Char>::value,
1794                            std::make_unsigned<Char>,
1795                            type_identity<uint32_t>>::type;
1796 
1797 template <typename Char>
1798 auto find_escape(const Char* begin, const Char* end)
1799     -> find_escape_result<Char> {
1800   for (; begin != end; ++begin) {
1801     uint32_t cp = static_cast<make_unsigned_char<Char>>(*begin);
1802     if (const_check(sizeof(Char) == 1) && cp >= 0x80) continue;
1803     if (needs_escape(cp)) return {begin, begin + 1, cp};
1804   }
1805   return {begin, nullptr, 0};
1806 }
1807 
1808 inline auto find_escape(const char* begin, const char* end)
1809     -> find_escape_result<char> {
1810   if (!is_utf8()) return find_escape<char>(begin, end);
1811   auto result = find_escape_result<char>{end, nullptr, 0};
1812   for_each_codepoint(string_view(begin, to_unsigned(end - begin)),
1813                      [&](uint32_t cp, string_view sv) {
1814                        if (needs_escape(cp)) {
1815                          result = {sv.begin(), sv.end(), cp};
1816                          return false;
1817                        }
1818                        return true;
1819                      });
1820   return result;
1821 }
1822 
1823 #define FMT_STRING_IMPL(s, base, explicit)                                    \
1824   [] {                                                                        \
1825     /* Use the hidden visibility as a workaround for a GCC bug (#1973). */    \
1826     /* Use a macro-like name to avoid shadowing warnings. */                  \
1827     struct FMT_VISIBILITY("hidden") FMT_COMPILE_STRING : base {               \
1828       using char_type FMT_MAYBE_UNUSED = fmt::remove_cvref_t<decltype(s[0])>; \
1829       FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit                                 \
1830       operator fmt::basic_string_view<char_type>() const {                    \
1831         return fmt::detail_exported::compile_string_to_view<char_type>(s);    \
1832       }                                                                       \
1833     };                                                                        \
1834     return FMT_COMPILE_STRING();                                              \
1835   }()
1836 
1837 /**
1838   \rst
1839   Constructs a compile-time format string from a string literal *s*.
1840 
1841   **Example**::
1842 
1843     // A compile-time error because 'd' is an invalid specifier for strings.
1844     std::string s = fmt::format(FMT_STRING("{:d}"), "foo");
1845   \endrst
1846  */
1847 #define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string, )
1848 
1849 template <size_t width, typename Char, typename OutputIt>
1850 auto write_codepoint(OutputIt out, char prefix, uint32_t cp) -> OutputIt {
1851   *out++ = static_cast<Char>('\\');
1852   *out++ = static_cast<Char>(prefix);
1853   Char buf[width];
1854   fill_n(buf, width, static_cast<Char>('0'));
1855   format_uint<4>(buf, cp, width);
1856   return copy_str<Char>(buf, buf + width, out);
1857 }
1858 
1859 template <typename OutputIt, typename Char>
1860 auto write_escaped_cp(OutputIt out, const find_escape_result<Char>& escape)
1861     -> OutputIt {
1862   auto c = static_cast<Char>(escape.cp);
1863   switch (escape.cp) {
1864   case '\n':
1865     *out++ = static_cast<Char>('\\');
1866     c = static_cast<Char>('n');
1867     break;
1868   case '\r':
1869     *out++ = static_cast<Char>('\\');
1870     c = static_cast<Char>('r');
1871     break;
1872   case '\t':
1873     *out++ = static_cast<Char>('\\');
1874     c = static_cast<Char>('t');
1875     break;
1876   case '"':
1877     FMT_FALLTHROUGH;
1878   case '\'':
1879     FMT_FALLTHROUGH;
1880   case '\\':
1881     *out++ = static_cast<Char>('\\');
1882     break;
1883   default:
1884     if (escape.cp < 0x100) {
1885       return write_codepoint<2, Char>(out, 'x', escape.cp);
1886     }
1887     if (escape.cp < 0x10000) {
1888       return write_codepoint<4, Char>(out, 'u', escape.cp);
1889     }
1890     if (escape.cp < 0x110000) {
1891       return write_codepoint<8, Char>(out, 'U', escape.cp);
1892     }
1893     for (Char escape_char : basic_string_view<Char>(
1894              escape.begin, to_unsigned(escape.end - escape.begin))) {
1895       out = write_codepoint<2, Char>(out, 'x',
1896                                      static_cast<uint32_t>(escape_char) & 0xFF);
1897     }
1898     return out;
1899   }
1900   *out++ = c;
1901   return out;
1902 }
1903 
1904 template <typename Char, typename OutputIt>
1905 auto write_escaped_string(OutputIt out, basic_string_view<Char> str)
1906     -> OutputIt {
1907   *out++ = static_cast<Char>('"');
1908   auto begin = str.begin(), end = str.end();
1909   do {
1910     auto escape = find_escape(begin, end);
1911     out = copy_str<Char>(begin, escape.begin, out);
1912     begin = escape.end;
1913     if (!begin) break;
1914     out = write_escaped_cp<OutputIt, Char>(out, escape);
1915   } while (begin != end);
1916   *out++ = static_cast<Char>('"');
1917   return out;
1918 }
1919 
1920 template <typename Char, typename OutputIt>
1921 auto write_escaped_char(OutputIt out, Char v) -> OutputIt {
1922   Char v_array[1] = {v};
1923   *out++ = static_cast<Char>('\'');
1924   if ((needs_escape(static_cast<uint32_t>(v)) && v != static_cast<Char>('"')) ||
1925       v == static_cast<Char>('\'')) {
1926     out = write_escaped_cp(out,
1927                            find_escape_result<Char>{v_array, v_array + 1,
1928                                                     static_cast<uint32_t>(v)});
1929   } else {
1930     *out++ = v;
1931   }
1932   *out++ = static_cast<Char>('\'');
1933   return out;
1934 }
1935 
1936 template <typename Char, typename OutputIt>
1937 FMT_CONSTEXPR auto write_char(OutputIt out, Char value,
1938                               const format_specs<Char>& specs) -> OutputIt {
1939   bool is_debug = specs.type == presentation_type::debug;
1940   return write_padded(out, specs, 1, [=](reserve_iterator<OutputIt> it) {
1941     if (is_debug) return write_escaped_char(it, value);
1942     *it++ = value;
1943     return it;
1944   });
1945 }
1946 template <typename Char, typename OutputIt>
1947 FMT_CONSTEXPR auto write(OutputIt out, Char value,
1948                          const format_specs<Char>& specs, locale_ref loc = {})
1949     -> OutputIt {
1950   // char is formatted as unsigned char for consistency across platforms.
1951   using unsigned_type =
1952       conditional_t<std::is_same<Char, char>::value, unsigned char, unsigned>;
1953   return check_char_specs(specs)
1954              ? write_char(out, value, specs)
1955              : write(out, static_cast<unsigned_type>(value), specs, loc);
1956 }
1957 
1958 // Data for write_int that doesn't depend on output iterator type. It is used to
1959 // avoid template code bloat.
1960 template <typename Char> struct write_int_data {
1961   size_t size;
1962   size_t padding;
1963 
1964   FMT_CONSTEXPR write_int_data(int num_digits, unsigned prefix,
1965                                const format_specs<Char>& specs)
1966       : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) {
1967     if (specs.align == align::numeric) {
1968       auto width = to_unsigned(specs.width);
1969       if (width > size) {
1970         padding = width - size;
1971         size = width;
1972       }
1973     } else if (specs.precision > num_digits) {
1974       size = (prefix >> 24) + to_unsigned(specs.precision);
1975       padding = to_unsigned(specs.precision - num_digits);
1976     }
1977   }
1978 };
1979 
1980 // Writes an integer in the format
1981 //   <left-padding><prefix><numeric-padding><digits><right-padding>
1982 // where <digits> are written by write_digits(it).
1983 // prefix contains chars in three lower bytes and the size in the fourth byte.
1984 template <typename OutputIt, typename Char, typename W>
1985 FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits,
1986                                         unsigned prefix,
1987                                         const format_specs<Char>& specs,
1988                                         W write_digits) -> OutputIt {
1989   // Slightly faster check for specs.width == 0 && specs.precision == -1.
1990   if ((specs.width | (specs.precision + 1)) == 0) {
1991     auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24));
1992     if (prefix != 0) {
1993       for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
1994         *it++ = static_cast<Char>(p & 0xff);
1995     }
1996     return base_iterator(out, write_digits(it));
1997   }
1998   auto data = write_int_data<Char>(num_digits, prefix, specs);
1999   return write_padded<align::right>(
2000       out, specs, data.size, [=](reserve_iterator<OutputIt> it) {
2001         for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
2002           *it++ = static_cast<Char>(p & 0xff);
2003         it = detail::fill_n(it, data.padding, static_cast<Char>('0'));
2004         return write_digits(it);
2005       });
2006 }
2007 
2008 template <typename Char> class digit_grouping {
2009  private:
2010   std::string grouping_;
2011   std::basic_string<Char> thousands_sep_;
2012 
2013   struct next_state {
2014     std::string::const_iterator group;
2015     int pos;
2016   };
2017   auto initial_state() const -> next_state { return {grouping_.begin(), 0}; }
2018 
2019   // Returns the next digit group separator position.
2020   auto next(next_state& state) const -> int {
2021     if (thousands_sep_.empty()) return max_value<int>();
2022     if (state.group == grouping_.end()) return state.pos += grouping_.back();
2023     if (*state.group <= 0 || *state.group == max_value<char>())
2024       return max_value<int>();
2025     state.pos += *state.group++;
2026     return state.pos;
2027   }
2028 
2029  public:
2030   explicit digit_grouping(locale_ref loc, bool localized = true) {
2031     if (!localized) return;
2032     auto sep = thousands_sep<Char>(loc);
2033     grouping_ = sep.grouping;
2034     if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep);
2035   }
2036   digit_grouping(std::string grouping, std::basic_string<Char> sep)
2037       : grouping_(std::move(grouping)), thousands_sep_(std::move(sep)) {}
2038 
2039   auto has_separator() const -> bool { return !thousands_sep_.empty(); }
2040 
2041   auto count_separators(int num_digits) const -> int {
2042     int count = 0;
2043     auto state = initial_state();
2044     while (num_digits > next(state)) ++count;
2045     return count;
2046   }
2047 
2048   // Applies grouping to digits and write the output to out.
2049   template <typename Out, typename C>
2050   auto apply(Out out, basic_string_view<C> digits) const -> Out {
2051     auto num_digits = static_cast<int>(digits.size());
2052     auto separators = basic_memory_buffer<int>();
2053     separators.push_back(0);
2054     auto state = initial_state();
2055     while (int i = next(state)) {
2056       if (i >= num_digits) break;
2057       separators.push_back(i);
2058     }
2059     for (int i = 0, sep_index = static_cast<int>(separators.size() - 1);
2060          i < num_digits; ++i) {
2061       if (num_digits - i == separators[sep_index]) {
2062         out =
2063             copy_str<Char>(thousands_sep_.data(),
2064                            thousands_sep_.data() + thousands_sep_.size(), out);
2065         --sep_index;
2066       }
2067       *out++ = static_cast<Char>(digits[to_unsigned(i)]);
2068     }
2069     return out;
2070   }
2071 };
2072 
2073 FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) {
2074   prefix |= prefix != 0 ? value << 8 : value;
2075   prefix += (1u + (value > 0xff ? 1 : 0)) << 24;
2076 }
2077 
2078 // Writes a decimal integer with digit grouping.
2079 template <typename OutputIt, typename UInt, typename Char>
2080 auto write_int(OutputIt out, UInt value, unsigned prefix,
2081                const format_specs<Char>& specs,
2082                const digit_grouping<Char>& grouping) -> OutputIt {
2083   static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value, "");
2084   int num_digits = 0;
2085   auto buffer = memory_buffer();
2086   switch (specs.type) {
2087   case presentation_type::none:
2088   case presentation_type::dec: {
2089     num_digits = count_digits(value);
2090     format_decimal<char>(appender(buffer), value, num_digits);
2091     break;
2092   }
2093   case presentation_type::hex_lower:
2094   case presentation_type::hex_upper: {
2095     bool upper = specs.type == presentation_type::hex_upper;
2096     if (specs.alt)
2097       prefix_append(prefix, unsigned(upper ? 'X' : 'x') << 8 | '0');
2098     num_digits = count_digits<4>(value);
2099     format_uint<4, char>(appender(buffer), value, num_digits, upper);
2100     break;
2101   }
2102   case presentation_type::bin_lower:
2103   case presentation_type::bin_upper: {
2104     bool upper = specs.type == presentation_type::bin_upper;
2105     if (specs.alt)
2106       prefix_append(prefix, unsigned(upper ? 'B' : 'b') << 8 | '0');
2107     num_digits = count_digits<1>(value);
2108     format_uint<1, char>(appender(buffer), value, num_digits);
2109     break;
2110   }
2111   case presentation_type::oct: {
2112     num_digits = count_digits<3>(value);
2113     // Octal prefix '0' is counted as a digit, so only add it if precision
2114     // is not greater than the number of digits.
2115     if (specs.alt && specs.precision <= num_digits && value != 0)
2116       prefix_append(prefix, '0');
2117     format_uint<3, char>(appender(buffer), value, num_digits);
2118     break;
2119   }
2120   case presentation_type::chr:
2121     return write_char(out, static_cast<Char>(value), specs);
2122   default:
2123     throw_format_error("invalid format specifier");
2124   }
2125 
2126   unsigned size = (prefix != 0 ? prefix >> 24 : 0) + to_unsigned(num_digits) +
2127                   to_unsigned(grouping.count_separators(num_digits));
2128   return write_padded<align::right>(
2129       out, specs, size, size, [&](reserve_iterator<OutputIt> it) {
2130         for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
2131           *it++ = static_cast<Char>(p & 0xff);
2132         return grouping.apply(it, string_view(buffer.data(), buffer.size()));
2133       });
2134 }
2135 
2136 // Writes a localized value.
2137 FMT_API auto write_loc(appender out, loc_value value,
2138                        const format_specs<>& specs, locale_ref loc) -> bool;
2139 template <typename OutputIt, typename Char>
2140 inline auto write_loc(OutputIt, loc_value, const format_specs<Char>&,
2141                       locale_ref) -> bool {
2142   return false;
2143 }
2144 
2145 template <typename UInt> struct write_int_arg {
2146   UInt abs_value;
2147   unsigned prefix;
2148 };
2149 
2150 template <typename T>
2151 FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign)
2152     -> write_int_arg<uint32_or_64_or_128_t<T>> {
2153   auto prefix = 0u;
2154   auto abs_value = static_cast<uint32_or_64_or_128_t<T>>(value);
2155   if (is_negative(value)) {
2156     prefix = 0x01000000 | '-';
2157     abs_value = 0 - abs_value;
2158   } else {
2159     constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+',
2160                                             0x1000000u | ' '};
2161     prefix = prefixes[sign];
2162   }
2163   return {abs_value, prefix};
2164 }
2165 
2166 template <typename Char = char> struct loc_writer {
2167   buffer_appender<Char> out;
2168   const format_specs<Char>& specs;
2169   std::basic_string<Char> sep;
2170   std::string grouping;
2171   std::basic_string<Char> decimal_point;
2172 
2173   template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
2174   auto operator()(T value) -> bool {
2175     auto arg = make_write_int_arg(value, specs.sign);
2176     write_int(out, static_cast<uint64_or_128_t<T>>(arg.abs_value), arg.prefix,
2177               specs, digit_grouping<Char>(grouping, sep));
2178     return true;
2179   }
2180 
2181   template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
2182   auto operator()(T) -> bool {
2183     return false;
2184   }
2185 };
2186 
2187 template <typename Char, typename OutputIt, typename T>
2188 FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg<T> arg,
2189                                         const format_specs<Char>& specs,
2190                                         locale_ref) -> OutputIt {
2191   static_assert(std::is_same<T, uint32_or_64_or_128_t<T>>::value, "");
2192   auto abs_value = arg.abs_value;
2193   auto prefix = arg.prefix;
2194   switch (specs.type) {
2195   case presentation_type::none:
2196   case presentation_type::dec: {
2197     auto num_digits = count_digits(abs_value);
2198     return write_int(
2199         out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
2200           return format_decimal<Char>(it, abs_value, num_digits).end;
2201         });
2202   }
2203   case presentation_type::hex_lower:
2204   case presentation_type::hex_upper: {
2205     bool upper = specs.type == presentation_type::hex_upper;
2206     if (specs.alt)
2207       prefix_append(prefix, unsigned(upper ? 'X' : 'x') << 8 | '0');
2208     int num_digits = count_digits<4>(abs_value);
2209     return write_int(
2210         out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
2211           return format_uint<4, Char>(it, abs_value, num_digits, upper);
2212         });
2213   }
2214   case presentation_type::bin_lower:
2215   case presentation_type::bin_upper: {
2216     bool upper = specs.type == presentation_type::bin_upper;
2217     if (specs.alt)
2218       prefix_append(prefix, unsigned(upper ? 'B' : 'b') << 8 | '0');
2219     int num_digits = count_digits<1>(abs_value);
2220     return write_int(out, num_digits, prefix, specs,
2221                      [=](reserve_iterator<OutputIt> it) {
2222                        return format_uint<1, Char>(it, abs_value, num_digits);
2223                      });
2224   }
2225   case presentation_type::oct: {
2226     int num_digits = count_digits<3>(abs_value);
2227     // Octal prefix '0' is counted as a digit, so only add it if precision
2228     // is not greater than the number of digits.
2229     if (specs.alt && specs.precision <= num_digits && abs_value != 0)
2230       prefix_append(prefix, '0');
2231     return write_int(out, num_digits, prefix, specs,
2232                      [=](reserve_iterator<OutputIt> it) {
2233                        return format_uint<3, Char>(it, abs_value, num_digits);
2234                      });
2235   }
2236   case presentation_type::chr:
2237     return write_char(out, static_cast<Char>(abs_value), specs);
2238   default:
2239     throw_format_error("invalid format specifier");
2240   }
2241   return out;
2242 }
2243 template <typename Char, typename OutputIt, typename T>
2244 FMT_CONSTEXPR FMT_NOINLINE auto write_int_noinline(
2245     OutputIt out, write_int_arg<T> arg, const format_specs<Char>& specs,
2246     locale_ref loc) -> OutputIt {
2247   return write_int(out, arg, specs, loc);
2248 }
2249 template <typename Char, typename OutputIt, typename T,
2250           FMT_ENABLE_IF(is_integral<T>::value &&
2251                         !std::is_same<T, bool>::value &&
2252                         std::is_same<OutputIt, buffer_appender<Char>>::value)>
2253 FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value,
2254                                     const format_specs<Char>& specs,
2255                                     locale_ref loc) -> OutputIt {
2256   if (specs.localized && write_loc(out, value, specs, loc)) return out;
2257   return write_int_noinline(out, make_write_int_arg(value, specs.sign), specs,
2258                             loc);
2259 }
2260 // An inlined version of write used in format string compilation.
2261 template <typename Char, typename OutputIt, typename T,
2262           FMT_ENABLE_IF(is_integral<T>::value &&
2263                         !std::is_same<T, bool>::value &&
2264                         !std::is_same<OutputIt, buffer_appender<Char>>::value)>
2265 FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value,
2266                                     const format_specs<Char>& specs,
2267                                     locale_ref loc) -> OutputIt {
2268   if (specs.localized && write_loc(out, value, specs, loc)) return out;
2269   return write_int(out, make_write_int_arg(value, specs.sign), specs, loc);
2270 }
2271 
2272 // An output iterator that counts the number of objects written to it and
2273 // discards them.
2274 class counting_iterator {
2275  private:
2276   size_t count_;
2277 
2278  public:
2279   using iterator_category = std::output_iterator_tag;
2280   using difference_type = std::ptrdiff_t;
2281   using pointer = void;
2282   using reference = void;
2283   FMT_UNCHECKED_ITERATOR(counting_iterator);
2284 
2285   struct value_type {
2286     template <typename T> FMT_CONSTEXPR void operator=(const T&) {}
2287   };
2288 
2289   FMT_CONSTEXPR counting_iterator() : count_(0) {}
2290 
2291   FMT_CONSTEXPR auto count() const -> size_t { return count_; }
2292 
2293   FMT_CONSTEXPR auto operator++() -> counting_iterator& {
2294     ++count_;
2295     return *this;
2296   }
2297   FMT_CONSTEXPR auto operator++(int) -> counting_iterator {
2298     auto it = *this;
2299     ++*this;
2300     return it;
2301   }
2302 
2303   FMT_CONSTEXPR friend auto operator+(counting_iterator it, difference_type n)
2304       -> counting_iterator {
2305     it.count_ += static_cast<size_t>(n);
2306     return it;
2307   }
2308 
2309   FMT_CONSTEXPR auto operator*() const -> value_type { return {}; }
2310 };
2311 
2312 template <typename Char, typename OutputIt>
2313 FMT_CONSTEXPR auto write(OutputIt out, basic_string_view<Char> s,
2314                          const format_specs<Char>& specs) -> OutputIt {
2315   auto data = s.data();
2316   auto size = s.size();
2317   if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
2318     size = code_point_index(s, to_unsigned(specs.precision));
2319   bool is_debug = specs.type == presentation_type::debug;
2320   size_t width = 0;
2321   if (specs.width != 0) {
2322     if (is_debug)
2323       width = write_escaped_string(counting_iterator{}, s).count();
2324     else
2325       width = compute_width(basic_string_view<Char>(data, size));
2326   }
2327   return write_padded(out, specs, size, width,
2328                       [=](reserve_iterator<OutputIt> it) {
2329                         if (is_debug) return write_escaped_string(it, s);
2330                         return copy_str<Char>(data, data + size, it);
2331                       });
2332 }
2333 template <typename Char, typename OutputIt>
2334 FMT_CONSTEXPR auto write(OutputIt out,
2335                          basic_string_view<type_identity_t<Char>> s,
2336                          const format_specs<Char>& specs, locale_ref)
2337     -> OutputIt {
2338   return write(out, s, specs);
2339 }
2340 template <typename Char, typename OutputIt>
2341 FMT_CONSTEXPR auto write(OutputIt out, const Char* s,
2342                          const format_specs<Char>& specs, locale_ref)
2343     -> OutputIt {
2344   if (specs.type == presentation_type::pointer)
2345     return write_ptr<Char>(out, bit_cast<uintptr_t>(s), &specs);
2346   if (!s) throw_format_error("string pointer is null");
2347   return write(out, basic_string_view<Char>(s), specs, {});
2348 }
2349 
2350 template <typename Char, typename OutputIt, typename T,
2351           FMT_ENABLE_IF(is_integral<T>::value &&
2352                         !std::is_same<T, bool>::value &&
2353                         !std::is_same<T, Char>::value)>
2354 FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt {
2355   auto abs_value = static_cast<uint32_or_64_or_128_t<T>>(value);
2356   bool negative = is_negative(value);
2357   // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer.
2358   if (negative) abs_value = ~abs_value + 1;
2359   int num_digits = count_digits(abs_value);
2360   auto size = (negative ? 1 : 0) + static_cast<size_t>(num_digits);
2361   auto it = reserve(out, size);
2362   if (auto ptr = to_pointer<Char>(it, size)) {
2363     if (negative) *ptr++ = static_cast<Char>('-');
2364     format_decimal<Char>(ptr, abs_value, num_digits);
2365     return out;
2366   }
2367   if (negative) *it++ = static_cast<Char>('-');
2368   it = format_decimal<Char>(it, abs_value, num_digits).end;
2369   return base_iterator(out, it);
2370 }
2371 
2372 // DEPRECATED!
2373 template <typename Char>
2374 FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
2375                                format_specs<Char>& specs) -> const Char* {
2376   FMT_ASSERT(begin != end, "");
2377   auto align = align::none;
2378   auto p = begin + code_point_length(begin);
2379   if (end - p <= 0) p = begin;
2380   for (;;) {
2381     switch (to_ascii(*p)) {
2382     case '<':
2383       align = align::left;
2384       break;
2385     case '>':
2386       align = align::right;
2387       break;
2388     case '^':
2389       align = align::center;
2390       break;
2391     }
2392     if (align != align::none) {
2393       if (p != begin) {
2394         auto c = *begin;
2395         if (c == '}') return begin;
2396         if (c == '{') {
2397           throw_format_error("invalid fill character '{'");
2398           return begin;
2399         }
2400         specs.fill = {begin, to_unsigned(p - begin)};
2401         begin = p + 1;
2402       } else {
2403         ++begin;
2404       }
2405       break;
2406     } else if (p == begin) {
2407       break;
2408     }
2409     p = begin;
2410   }
2411   specs.align = align;
2412   return begin;
2413 }
2414 
2415 // A floating-point presentation format.
2416 enum class float_format : unsigned char {
2417   general,  // General: exponent notation or fixed point based on magnitude.
2418   exp,      // Exponent notation with the default precision of 6, e.g. 1.2e-3.
2419   fixed,    // Fixed point with the default precision of 6, e.g. 0.0012.
2420   hex
2421 };
2422 
2423 struct float_specs {
2424   int precision;
2425   float_format format : 8;
2426   sign_t sign : 8;
2427   bool upper : 1;
2428   bool locale : 1;
2429   bool binary32 : 1;
2430   bool showpoint : 1;
2431 };
2432 
2433 template <typename Char>
2434 FMT_CONSTEXPR auto parse_float_type_spec(const format_specs<Char>& specs)
2435     -> float_specs {
2436   auto result = float_specs();
2437   result.showpoint = specs.alt;
2438   result.locale = specs.localized;
2439   switch (specs.type) {
2440   case presentation_type::none:
2441     result.format = float_format::general;
2442     break;
2443   case presentation_type::general_upper:
2444     result.upper = true;
2445     FMT_FALLTHROUGH;
2446   case presentation_type::general_lower:
2447     result.format = float_format::general;
2448     break;
2449   case presentation_type::exp_upper:
2450     result.upper = true;
2451     FMT_FALLTHROUGH;
2452   case presentation_type::exp_lower:
2453     result.format = float_format::exp;
2454     result.showpoint |= specs.precision != 0;
2455     break;
2456   case presentation_type::fixed_upper:
2457     result.upper = true;
2458     FMT_FALLTHROUGH;
2459   case presentation_type::fixed_lower:
2460     result.format = float_format::fixed;
2461     result.showpoint |= specs.precision != 0;
2462     break;
2463   case presentation_type::hexfloat_upper:
2464     result.upper = true;
2465     FMT_FALLTHROUGH;
2466   case presentation_type::hexfloat_lower:
2467     result.format = float_format::hex;
2468     break;
2469   default:
2470     throw_format_error("invalid format specifier");
2471     break;
2472   }
2473   return result;
2474 }
2475 
2476 template <typename Char, typename OutputIt>
2477 FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan,
2478                                      format_specs<Char> specs,
2479                                      const float_specs& fspecs) -> OutputIt {
2480   auto str =
2481       isnan ? (fspecs.upper ? "NAN" : "nan") : (fspecs.upper ? "INF" : "inf");
2482   constexpr size_t str_size = 3;
2483   auto sign = fspecs.sign;
2484   auto size = str_size + (sign ? 1 : 0);
2485   // Replace '0'-padding with space for non-finite values.
2486   const bool is_zero_fill =
2487       specs.fill.size() == 1 && *specs.fill.data() == static_cast<Char>('0');
2488   if (is_zero_fill) specs.fill[0] = static_cast<Char>(' ');
2489   return write_padded(out, specs, size, [=](reserve_iterator<OutputIt> it) {
2490     if (sign) *it++ = detail::sign<Char>(sign);
2491     return copy_str<Char>(str, str + str_size, it);
2492   });
2493 }
2494 
2495 // A decimal floating-point number significand * pow(10, exp).
2496 struct big_decimal_fp {
2497   const char* significand;
2498   int significand_size;
2499   int exponent;
2500 };
2501 
2502 constexpr auto get_significand_size(const big_decimal_fp& f) -> int {
2503   return f.significand_size;
2504 }
2505 template <typename T>
2506 inline auto get_significand_size(const dragonbox::decimal_fp<T>& f) -> int {
2507   return count_digits(f.significand);
2508 }
2509 
2510 template <typename Char, typename OutputIt>
2511 constexpr auto write_significand(OutputIt out, const char* significand,
2512                                  int significand_size) -> OutputIt {
2513   return copy_str<Char>(significand, significand + significand_size, out);
2514 }
2515 template <typename Char, typename OutputIt, typename UInt>
2516 inline auto write_significand(OutputIt out, UInt significand,
2517                               int significand_size) -> OutputIt {
2518   return format_decimal<Char>(out, significand, significand_size).end;
2519 }
2520 template <typename Char, typename OutputIt, typename T, typename Grouping>
2521 FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand,
2522                                        int significand_size, int exponent,
2523                                        const Grouping& grouping) -> OutputIt {
2524   if (!grouping.has_separator()) {
2525     out = write_significand<Char>(out, significand, significand_size);
2526     return detail::fill_n(out, exponent, static_cast<Char>('0'));
2527   }
2528   auto buffer = memory_buffer();
2529   write_significand<char>(appender(buffer), significand, significand_size);
2530   detail::fill_n(appender(buffer), exponent, '0');
2531   return grouping.apply(out, string_view(buffer.data(), buffer.size()));
2532 }
2533 
2534 template <typename Char, typename UInt,
2535           FMT_ENABLE_IF(std::is_integral<UInt>::value)>
2536 inline auto write_significand(Char* out, UInt significand, int significand_size,
2537                               int integral_size, Char decimal_point) -> Char* {
2538   if (!decimal_point)
2539     return format_decimal(out, significand, significand_size).end;
2540   out += significand_size + 1;
2541   Char* end = out;
2542   int floating_size = significand_size - integral_size;
2543   for (int i = floating_size / 2; i > 0; --i) {
2544     out -= 2;
2545     copy2(out, digits2(static_cast<std::size_t>(significand % 100)));
2546     significand /= 100;
2547   }
2548   if (floating_size % 2 != 0) {
2549     *--out = static_cast<Char>('0' + significand % 10);
2550     significand /= 10;
2551   }
2552   *--out = decimal_point;
2553   format_decimal(out - integral_size, significand, integral_size);
2554   return end;
2555 }
2556 
2557 template <typename OutputIt, typename UInt, typename Char,
2558           FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)>
2559 inline auto write_significand(OutputIt out, UInt significand,
2560                               int significand_size, int integral_size,
2561                               Char decimal_point) -> OutputIt {
2562   // Buffer is large enough to hold digits (digits10 + 1) and a decimal point.
2563   Char buffer[digits10<UInt>() + 2];
2564   auto end = write_significand(buffer, significand, significand_size,
2565                                integral_size, decimal_point);
2566   return detail::copy_str_noinline<Char>(buffer, end, out);
2567 }
2568 
2569 template <typename OutputIt, typename Char>
2570 FMT_CONSTEXPR auto write_significand(OutputIt out, const char* significand,
2571                                      int significand_size, int integral_size,
2572                                      Char decimal_point) -> OutputIt {
2573   out = detail::copy_str_noinline<Char>(significand,
2574                                         significand + integral_size, out);
2575   if (!decimal_point) return out;
2576   *out++ = decimal_point;
2577   return detail::copy_str_noinline<Char>(significand + integral_size,
2578                                          significand + significand_size, out);
2579 }
2580 
2581 template <typename OutputIt, typename Char, typename T, typename Grouping>
2582 FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand,
2583                                        int significand_size, int integral_size,
2584                                        Char decimal_point,
2585                                        const Grouping& grouping) -> OutputIt {
2586   if (!grouping.has_separator()) {
2587     return write_significand(out, significand, significand_size, integral_size,
2588                              decimal_point);
2589   }
2590   auto buffer = basic_memory_buffer<Char>();
2591   write_significand(buffer_appender<Char>(buffer), significand,
2592                     significand_size, integral_size, decimal_point);
2593   grouping.apply(
2594       out, basic_string_view<Char>(buffer.data(), to_unsigned(integral_size)));
2595   return detail::copy_str_noinline<Char>(buffer.data() + integral_size,
2596                                          buffer.end(), out);
2597 }
2598 
2599 template <typename OutputIt, typename DecimalFP, typename Char,
2600           typename Grouping = digit_grouping<Char>>
2601 FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
2602                                     const format_specs<Char>& specs,
2603                                     float_specs fspecs, locale_ref loc)
2604     -> OutputIt {
2605   auto significand = f.significand;
2606   int significand_size = get_significand_size(f);
2607   const Char zero = static_cast<Char>('0');
2608   auto sign = fspecs.sign;
2609   size_t size = to_unsigned(significand_size) + (sign ? 1 : 0);
2610   using iterator = reserve_iterator<OutputIt>;
2611 
2612   Char decimal_point =
2613       fspecs.locale ? detail::decimal_point<Char>(loc) : static_cast<Char>('.');
2614 
2615   int output_exp = f.exponent + significand_size - 1;
2616   auto use_exp_format = [=]() {
2617     if (fspecs.format == float_format::exp) return true;
2618     if (fspecs.format != float_format::general) return false;
2619     // Use the fixed notation if the exponent is in [exp_lower, exp_upper),
2620     // e.g. 0.0001 instead of 1e-04. Otherwise use the exponent notation.
2621     const int exp_lower = -4, exp_upper = 16;
2622     return output_exp < exp_lower ||
2623            output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper);
2624   };
2625   if (use_exp_format()) {
2626     int num_zeros = 0;
2627     if (fspecs.showpoint) {
2628       num_zeros = fspecs.precision - significand_size;
2629       if (num_zeros < 0) num_zeros = 0;
2630       size += to_unsigned(num_zeros);
2631     } else if (significand_size == 1) {
2632       decimal_point = Char();
2633     }
2634     auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp;
2635     int exp_digits = 2;
2636     if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3;
2637 
2638     size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits);
2639     char exp_char = fspecs.upper ? 'E' : 'e';
2640     auto write = [=](iterator it) {
2641       if (sign) *it++ = detail::sign<Char>(sign);
2642       // Insert a decimal point after the first digit and add an exponent.
2643       it = write_significand(it, significand, significand_size, 1,
2644                              decimal_point);
2645       if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero);
2646       *it++ = static_cast<Char>(exp_char);
2647       return write_exponent<Char>(output_exp, it);
2648     };
2649     return specs.width > 0 ? write_padded<align::right>(out, specs, size, write)
2650                            : base_iterator(out, write(reserve(out, size)));
2651   }
2652 
2653   int exp = f.exponent + significand_size;
2654   if (f.exponent >= 0) {
2655     // 1234e5 -> 123400000[.0+]
2656     size += to_unsigned(f.exponent);
2657     int num_zeros = fspecs.precision - exp;
2658     abort_fuzzing_if(num_zeros > 5000);
2659     if (fspecs.showpoint) {
2660       ++size;
2661       if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 0;
2662       if (num_zeros > 0) size += to_unsigned(num_zeros);
2663     }
2664     auto grouping = Grouping(loc, fspecs.locale);
2665     size += to_unsigned(grouping.count_separators(exp));
2666     return write_padded<align::right>(out, specs, size, [&](iterator it) {
2667       if (sign) *it++ = detail::sign<Char>(sign);
2668       it = write_significand<Char>(it, significand, significand_size,
2669                                    f.exponent, grouping);
2670       if (!fspecs.showpoint) return it;
2671       *it++ = decimal_point;
2672       return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
2673     });
2674   } else if (exp > 0) {
2675     // 1234e-2 -> 12.34[0+]
2676     int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0;
2677     size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0);
2678     auto grouping = Grouping(loc, fspecs.locale);
2679     size += to_unsigned(grouping.count_separators(exp));
2680     return write_padded<align::right>(out, specs, size, [&](iterator it) {
2681       if (sign) *it++ = detail::sign<Char>(sign);
2682       it = write_significand(it, significand, significand_size, exp,
2683                              decimal_point, grouping);
2684       return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
2685     });
2686   }
2687   // 1234e-6 -> 0.001234
2688   int num_zeros = -exp;
2689   if (significand_size == 0 && fspecs.precision >= 0 &&
2690       fspecs.precision < num_zeros) {
2691     num_zeros = fspecs.precision;
2692   }
2693   bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint;
2694   size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros);
2695   return write_padded<align::right>(out, specs, size, [&](iterator it) {
2696     if (sign) *it++ = detail::sign<Char>(sign);
2697     *it++ = zero;
2698     if (!pointy) return it;
2699     *it++ = decimal_point;
2700     it = detail::fill_n(it, num_zeros, zero);
2701     return write_significand<Char>(it, significand, significand_size);
2702   });
2703 }
2704 
2705 template <typename Char> class fallback_digit_grouping {
2706  public:
2707   constexpr fallback_digit_grouping(locale_ref, bool) {}
2708 
2709   constexpr auto has_separator() const -> bool { return false; }
2710 
2711   constexpr auto count_separators(int) const -> int { return 0; }
2712 
2713   template <typename Out, typename C>
2714   constexpr auto apply(Out out, basic_string_view<C>) const -> Out {
2715     return out;
2716   }
2717 };
2718 
2719 template <typename OutputIt, typename DecimalFP, typename Char>
2720 FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& f,
2721                                  const format_specs<Char>& specs,
2722                                  float_specs fspecs, locale_ref loc)
2723     -> OutputIt {
2724   if (is_constant_evaluated()) {
2725     return do_write_float<OutputIt, DecimalFP, Char,
2726                           fallback_digit_grouping<Char>>(out, f, specs, fspecs,
2727                                                          loc);
2728   } else {
2729     return do_write_float(out, f, specs, fspecs, loc);
2730   }
2731 }
2732 
2733 template <typename T> constexpr auto isnan(T value) -> bool {
2734   return !(value >= value);  // std::isnan doesn't support __float128.
2735 }
2736 
2737 template <typename T, typename Enable = void>
2738 struct has_isfinite : std::false_type {};
2739 
2740 template <typename T>
2741 struct has_isfinite<T, enable_if_t<sizeof(std::isfinite(T())) != 0>>
2742     : std::true_type {};
2743 
2744 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value&&
2745                                         has_isfinite<T>::value)>
2746 FMT_CONSTEXPR20 auto isfinite(T value) -> bool {
2747   constexpr T inf = T(std::numeric_limits<double>::infinity());
2748   if (is_constant_evaluated(true))
2749     return !detail::isnan(value) && value < inf && value > -inf;
2750   return std::isfinite(value);
2751 }
2752 template <typename T, FMT_ENABLE_IF(!has_isfinite<T>::value)>
2753 FMT_CONSTEXPR auto isfinite(T value) -> bool {
2754   T inf = T(std::numeric_limits<double>::infinity());
2755   // std::isfinite doesn't support __float128.
2756   return !detail::isnan(value) && value < inf && value > -inf;
2757 }
2758 
2759 template <typename T, FMT_ENABLE_IF(is_floating_point<T>::value)>
2760 FMT_INLINE FMT_CONSTEXPR bool signbit(T value) {
2761   if (is_constant_evaluated()) {
2762 #ifdef __cpp_if_constexpr
2763     if constexpr (std::numeric_limits<double>::is_iec559) {
2764       auto bits = detail::bit_cast<uint64_t>(static_cast<double>(value));
2765       return (bits >> (num_bits<uint64_t>() - 1)) != 0;
2766     }
2767 #endif
2768   }
2769   return std::signbit(static_cast<double>(value));
2770 }
2771 
2772 inline FMT_CONSTEXPR20 void adjust_precision(int& precision, int exp10) {
2773   // Adjust fixed precision by exponent because it is relative to decimal
2774   // point.
2775   if (exp10 > 0 && precision > max_value<int>() - exp10)
2776     FMT_THROW(format_error("number is too big"));
2777   precision += exp10;
2778 }
2779 
2780 class bigint {
2781  private:
2782   // A bigint is stored as an array of bigits (big digits), with bigit at index
2783   // 0 being the least significant one.
2784   using bigit = uint32_t;
2785   using double_bigit = uint64_t;
2786   enum { bigits_capacity = 32 };
2787   basic_memory_buffer<bigit, bigits_capacity> bigits_;
2788   int exp_;
2789 
2790   FMT_CONSTEXPR20 auto operator[](int index) const -> bigit {
2791     return bigits_[to_unsigned(index)];
2792   }
2793   FMT_CONSTEXPR20 auto operator[](int index) -> bigit& {
2794     return bigits_[to_unsigned(index)];
2795   }
2796 
2797   static constexpr const int bigit_bits = num_bits<bigit>();
2798 
2799   friend struct formatter<bigint>;
2800 
2801   FMT_CONSTEXPR20 void subtract_bigits(int index, bigit other, bigit& borrow) {
2802     auto result = static_cast<double_bigit>((*this)[index]) - other - borrow;
2803     (*this)[index] = static_cast<bigit>(result);
2804     borrow = static_cast<bigit>(result >> (bigit_bits * 2 - 1));
2805   }
2806 
2807   FMT_CONSTEXPR20 void remove_leading_zeros() {
2808     int num_bigits = static_cast<int>(bigits_.size()) - 1;
2809     while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits;
2810     bigits_.resize(to_unsigned(num_bigits + 1));
2811   }
2812 
2813   // Computes *this -= other assuming aligned bigints and *this >= other.
2814   FMT_CONSTEXPR20 void subtract_aligned(const bigint& other) {
2815     FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints");
2816     FMT_ASSERT(compare(*this, other) >= 0, "");
2817     bigit borrow = 0;
2818     int i = other.exp_ - exp_;
2819     for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j)
2820       subtract_bigits(i, other.bigits_[j], borrow);
2821     while (borrow > 0) subtract_bigits(i, 0, borrow);
2822     remove_leading_zeros();
2823   }
2824 
2825   FMT_CONSTEXPR20 void multiply(uint32_t value) {
2826     const double_bigit wide_value = value;
2827     bigit carry = 0;
2828     for (size_t i = 0, n = bigits_.size(); i < n; ++i) {
2829       double_bigit result = bigits_[i] * wide_value + carry;
2830       bigits_[i] = static_cast<bigit>(result);
2831       carry = static_cast<bigit>(result >> bigit_bits);
2832     }
2833     if (carry != 0) bigits_.push_back(carry);
2834   }
2835 
2836   template <typename UInt, FMT_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
2837                                          std::is_same<UInt, uint128_t>::value)>
2838   FMT_CONSTEXPR20 void multiply(UInt value) {
2839     using half_uint =
2840         conditional_t<std::is_same<UInt, uint128_t>::value, uint64_t, uint32_t>;
2841     const int shift = num_bits<half_uint>() - bigit_bits;
2842     const UInt lower = static_cast<half_uint>(value);
2843     const UInt upper = value >> num_bits<half_uint>();
2844     UInt carry = 0;
2845     for (size_t i = 0, n = bigits_.size(); i < n; ++i) {
2846       UInt result = lower * bigits_[i] + static_cast<bigit>(carry);
2847       carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) +
2848               (carry >> bigit_bits);
2849       bigits_[i] = static_cast<bigit>(result);
2850     }
2851     while (carry != 0) {
2852       bigits_.push_back(static_cast<bigit>(carry));
2853       carry >>= bigit_bits;
2854     }
2855   }
2856 
2857   template <typename UInt, FMT_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
2858                                          std::is_same<UInt, uint128_t>::value)>
2859   FMT_CONSTEXPR20 void assign(UInt n) {
2860     size_t num_bigits = 0;
2861     do {
2862       bigits_[num_bigits++] = static_cast<bigit>(n);
2863       n >>= bigit_bits;
2864     } while (n != 0);
2865     bigits_.resize(num_bigits);
2866     exp_ = 0;
2867   }
2868 
2869  public:
2870   FMT_CONSTEXPR20 bigint() : exp_(0) {}
2871   explicit bigint(uint64_t n) { assign(n); }
2872 
2873   bigint(const bigint&) = delete;
2874   void operator=(const bigint&) = delete;
2875 
2876   FMT_CONSTEXPR20 void assign(const bigint& other) {
2877     auto size = other.bigits_.size();
2878     bigits_.resize(size);
2879     auto data = other.bigits_.data();
2880     copy_str<bigit>(data, data + size, bigits_.data());
2881     exp_ = other.exp_;
2882   }
2883 
2884   template <typename Int> FMT_CONSTEXPR20 void operator=(Int n) {
2885     FMT_ASSERT(n > 0, "");
2886     assign(uint64_or_128_t<Int>(n));
2887   }
2888 
2889   FMT_CONSTEXPR20 auto num_bigits() const -> int {
2890     return static_cast<int>(bigits_.size()) + exp_;
2891   }
2892 
2893   FMT_NOINLINE FMT_CONSTEXPR20 auto operator<<=(int shift) -> bigint& {
2894     FMT_ASSERT(shift >= 0, "");
2895     exp_ += shift / bigit_bits;
2896     shift %= bigit_bits;
2897     if (shift == 0) return *this;
2898     bigit carry = 0;
2899     for (size_t i = 0, n = bigits_.size(); i < n; ++i) {
2900       bigit c = bigits_[i] >> (bigit_bits - shift);
2901       bigits_[i] = (bigits_[i] << shift) + carry;
2902       carry = c;
2903     }
2904     if (carry != 0) bigits_.push_back(carry);
2905     return *this;
2906   }
2907 
2908   template <typename Int>
2909   FMT_CONSTEXPR20 auto operator*=(Int value) -> bigint& {
2910     FMT_ASSERT(value > 0, "");
2911     multiply(uint32_or_64_or_128_t<Int>(value));
2912     return *this;
2913   }
2914 
2915   friend FMT_CONSTEXPR20 auto compare(const bigint& lhs, const bigint& rhs)
2916       -> int {
2917     int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits();
2918     if (num_lhs_bigits != num_rhs_bigits)
2919       return num_lhs_bigits > num_rhs_bigits ? 1 : -1;
2920     int i = static_cast<int>(lhs.bigits_.size()) - 1;
2921     int j = static_cast<int>(rhs.bigits_.size()) - 1;
2922     int end = i - j;
2923     if (end < 0) end = 0;
2924     for (; i >= end; --i, --j) {
2925       bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j];
2926       if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1;
2927     }
2928     if (i != j) return i > j ? 1 : -1;
2929     return 0;
2930   }
2931 
2932   // Returns compare(lhs1 + lhs2, rhs).
2933   friend FMT_CONSTEXPR20 auto add_compare(const bigint& lhs1,
2934                                           const bigint& lhs2, const bigint& rhs)
2935       -> int {
2936     auto minimum = [](int a, int b) { return a < b ? a : b; };
2937     auto maximum = [](int a, int b) { return a > b ? a : b; };
2938     int max_lhs_bigits = maximum(lhs1.num_bigits(), lhs2.num_bigits());
2939     int num_rhs_bigits = rhs.num_bigits();
2940     if (max_lhs_bigits + 1 < num_rhs_bigits) return -1;
2941     if (max_lhs_bigits > num_rhs_bigits) return 1;
2942     auto get_bigit = [](const bigint& n, int i) -> bigit {
2943       return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0;
2944     };
2945     double_bigit borrow = 0;
2946     int min_exp = minimum(minimum(lhs1.exp_, lhs2.exp_), rhs.exp_);
2947     for (int i = num_rhs_bigits - 1; i >= min_exp; --i) {
2948       double_bigit sum =
2949           static_cast<double_bigit>(get_bigit(lhs1, i)) + get_bigit(lhs2, i);
2950       bigit rhs_bigit = get_bigit(rhs, i);
2951       if (sum > rhs_bigit + borrow) return 1;
2952       borrow = rhs_bigit + borrow - sum;
2953       if (borrow > 1) return -1;
2954       borrow <<= bigit_bits;
2955     }
2956     return borrow != 0 ? -1 : 0;
2957   }
2958 
2959   // Assigns pow(10, exp) to this bigint.
2960   FMT_CONSTEXPR20 void assign_pow10(int exp) {
2961     FMT_ASSERT(exp >= 0, "");
2962     if (exp == 0) return *this = 1;
2963     // Find the top bit.
2964     int bitmask = 1;
2965     while (exp >= bitmask) bitmask <<= 1;
2966     bitmask >>= 1;
2967     // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by
2968     // repeated squaring and multiplication.
2969     *this = 5;
2970     bitmask >>= 1;
2971     while (bitmask != 0) {
2972       square();
2973       if ((exp & bitmask) != 0) *this *= 5;
2974       bitmask >>= 1;
2975     }
2976     *this <<= exp;  // Multiply by pow(2, exp) by shifting.
2977   }
2978 
2979   FMT_CONSTEXPR20 void square() {
2980     int num_bigits = static_cast<int>(bigits_.size());
2981     int num_result_bigits = 2 * num_bigits;
2982     basic_memory_buffer<bigit, bigits_capacity> n(std::move(bigits_));
2983     bigits_.resize(to_unsigned(num_result_bigits));
2984     auto sum = uint128_t();
2985     for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) {
2986       // Compute bigit at position bigit_index of the result by adding
2987       // cross-product terms n[i] * n[j] such that i + j == bigit_index.
2988       for (int i = 0, j = bigit_index; j >= 0; ++i, --j) {
2989         // Most terms are multiplied twice which can be optimized in the future.
2990         sum += static_cast<double_bigit>(n[i]) * n[j];
2991       }
2992       (*this)[bigit_index] = static_cast<bigit>(sum);
2993       sum >>= num_bits<bigit>();  // Compute the carry.
2994     }
2995     // Do the same for the top half.
2996     for (int bigit_index = num_bigits; bigit_index < num_result_bigits;
2997          ++bigit_index) {
2998       for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;)
2999         sum += static_cast<double_bigit>(n[i++]) * n[j--];
3000       (*this)[bigit_index] = static_cast<bigit>(sum);
3001       sum >>= num_bits<bigit>();
3002     }
3003     remove_leading_zeros();
3004     exp_ *= 2;
3005   }
3006 
3007   // If this bigint has a bigger exponent than other, adds trailing zero to make
3008   // exponents equal. This simplifies some operations such as subtraction.
3009   FMT_CONSTEXPR20 void align(const bigint& other) {
3010     int exp_difference = exp_ - other.exp_;
3011     if (exp_difference <= 0) return;
3012     int num_bigits = static_cast<int>(bigits_.size());
3013     bigits_.resize(to_unsigned(num_bigits + exp_difference));
3014     for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j)
3015       bigits_[j] = bigits_[i];
3016     std::uninitialized_fill_n(bigits_.data(), exp_difference, 0u);
3017     exp_ -= exp_difference;
3018   }
3019 
3020   // Divides this bignum by divisor, assigning the remainder to this and
3021   // returning the quotient.
3022   FMT_CONSTEXPR20 auto divmod_assign(const bigint& divisor) -> int {
3023     FMT_ASSERT(this != &divisor, "");
3024     if (compare(*this, divisor) < 0) return 0;
3025     FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, "");
3026     align(divisor);
3027     int quotient = 0;
3028     do {
3029       subtract_aligned(divisor);
3030       ++quotient;
3031     } while (compare(*this, divisor) >= 0);
3032     return quotient;
3033   }
3034 };
3035 
3036 // format_dragon flags.
3037 enum dragon {
3038   predecessor_closer = 1,
3039   fixup = 2,  // Run fixup to correct exp10 which can be off by one.
3040   fixed = 4,
3041 };
3042 
3043 // Formats a floating-point number using a variation of the Fixed-Precision
3044 // Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White:
3045 // https://fmt.dev/papers/p372-steele.pdf.
3046 FMT_CONSTEXPR20 inline void format_dragon(basic_fp<uint128_t> value,
3047                                           unsigned flags, int num_digits,
3048                                           buffer<char>& buf, int& exp10) {
3049   bigint numerator;    // 2 * R in (FPP)^2.
3050   bigint denominator;  // 2 * S in (FPP)^2.
3051   // lower and upper are differences between value and corresponding boundaries.
3052   bigint lower;             // (M^- in (FPP)^2).
3053   bigint upper_store;       // upper's value if different from lower.
3054   bigint* upper = nullptr;  // (M^+ in (FPP)^2).
3055   // Shift numerator and denominator by an extra bit or two (if lower boundary
3056   // is closer) to make lower and upper integers. This eliminates multiplication
3057   // by 2 during later computations.
3058   bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0;
3059   int shift = is_predecessor_closer ? 2 : 1;
3060   if (value.e >= 0) {
3061     numerator = value.f;
3062     numerator <<= value.e + shift;
3063     lower = 1;
3064     lower <<= value.e;
3065     if (is_predecessor_closer) {
3066       upper_store = 1;
3067       upper_store <<= value.e + 1;
3068       upper = &upper_store;
3069     }
3070     denominator.assign_pow10(exp10);
3071     denominator <<= shift;
3072   } else if (exp10 < 0) {
3073     numerator.assign_pow10(-exp10);
3074     lower.assign(numerator);
3075     if (is_predecessor_closer) {
3076       upper_store.assign(numerator);
3077       upper_store <<= 1;
3078       upper = &upper_store;
3079     }
3080     numerator *= value.f;
3081     numerator <<= shift;
3082     denominator = 1;
3083     denominator <<= shift - value.e;
3084   } else {
3085     numerator = value.f;
3086     numerator <<= shift;
3087     denominator.assign_pow10(exp10);
3088     denominator <<= shift - value.e;
3089     lower = 1;
3090     if (is_predecessor_closer) {
3091       upper_store = 1ULL << 1;
3092       upper = &upper_store;
3093     }
3094   }
3095   int even = static_cast<int>((value.f & 1) == 0);
3096   if (!upper) upper = &lower;
3097   bool shortest = num_digits < 0;
3098   if ((flags & dragon::fixup) != 0) {
3099     if (add_compare(numerator, *upper, denominator) + even <= 0) {
3100       --exp10;
3101       numerator *= 10;
3102       if (num_digits < 0) {
3103         lower *= 10;
3104         if (upper != &lower) *upper *= 10;
3105       }
3106     }
3107     if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1);
3108   }
3109   // Invariant: value == (numerator / denominator) * pow(10, exp10).
3110   if (shortest) {
3111     // Generate the shortest representation.
3112     num_digits = 0;
3113     char* data = buf.data();
3114     for (;;) {
3115       int digit = numerator.divmod_assign(denominator);
3116       bool low = compare(numerator, lower) - even < 0;  // numerator <[=] lower.
3117       // numerator + upper >[=] pow10:
3118       bool high = add_compare(numerator, *upper, denominator) + even > 0;
3119       data[num_digits++] = static_cast<char>('0' + digit);
3120       if (low || high) {
3121         if (!low) {
3122           ++data[num_digits - 1];
3123         } else if (high) {
3124           int result = add_compare(numerator, numerator, denominator);
3125           // Round half to even.
3126           if (result > 0 || (result == 0 && (digit % 2) != 0))
3127             ++data[num_digits - 1];
3128         }
3129         buf.try_resize(to_unsigned(num_digits));
3130         exp10 -= num_digits - 1;
3131         return;
3132       }
3133       numerator *= 10;
3134       lower *= 10;
3135       if (upper != &lower) *upper *= 10;
3136     }
3137   }
3138   // Generate the given number of digits.
3139   exp10 -= num_digits - 1;
3140   if (num_digits <= 0) {
3141     denominator *= 10;
3142     auto digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0';
3143     buf.push_back(digit);
3144     return;
3145   }
3146   buf.try_resize(to_unsigned(num_digits));
3147   for (int i = 0; i < num_digits - 1; ++i) {
3148     int digit = numerator.divmod_assign(denominator);
3149     buf[i] = static_cast<char>('0' + digit);
3150     numerator *= 10;
3151   }
3152   int digit = numerator.divmod_assign(denominator);
3153   auto result = add_compare(numerator, numerator, denominator);
3154   if (result > 0 || (result == 0 && (digit % 2) != 0)) {
3155     if (digit == 9) {
3156       const auto overflow = '0' + 10;
3157       buf[num_digits - 1] = overflow;
3158       // Propagate the carry.
3159       for (int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) {
3160         buf[i] = '0';
3161         ++buf[i - 1];
3162       }
3163       if (buf[0] == overflow) {
3164         buf[0] = '1';
3165         if ((flags & dragon::fixed) != 0)
3166           buf.push_back('0');
3167         else
3168           ++exp10;
3169       }
3170       return;
3171     }
3172     ++digit;
3173   }
3174   buf[num_digits - 1] = static_cast<char>('0' + digit);
3175 }
3176 
3177 // Formats a floating-point number using the hexfloat format.
3178 template <typename Float, FMT_ENABLE_IF(!is_double_double<Float>::value)>
3179 FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
3180                                      float_specs specs, buffer<char>& buf) {
3181   // float is passed as double to reduce the number of instantiations and to
3182   // simplify implementation.
3183   static_assert(!std::is_same<Float, float>::value, "");
3184 
3185   using info = dragonbox::float_info<Float>;
3186 
3187   // Assume Float is in the format [sign][exponent][significand].
3188   using carrier_uint = typename info::carrier_uint;
3189 
3190   constexpr auto num_float_significand_bits =
3191       detail::num_significand_bits<Float>();
3192 
3193   basic_fp<carrier_uint> f(value);
3194   f.e += num_float_significand_bits;
3195   if (!has_implicit_bit<Float>()) --f.e;
3196 
3197   constexpr auto num_fraction_bits =
3198       num_float_significand_bits + (has_implicit_bit<Float>() ? 1 : 0);
3199   constexpr auto num_xdigits = (num_fraction_bits + 3) / 4;
3200 
3201   constexpr auto leading_shift = ((num_xdigits - 1) * 4);
3202   const auto leading_mask = carrier_uint(0xF) << leading_shift;
3203   const auto leading_xdigit =
3204       static_cast<uint32_t>((f.f & leading_mask) >> leading_shift);
3205   if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1);
3206 
3207   int print_xdigits = num_xdigits - 1;
3208   if (precision >= 0 && print_xdigits > precision) {
3209     const int shift = ((print_xdigits - precision - 1) * 4);
3210     const auto mask = carrier_uint(0xF) << shift;
3211     const auto v = static_cast<uint32_t>((f.f & mask) >> shift);
3212 
3213     if (v >= 8) {
3214       const auto inc = carrier_uint(1) << (shift + 4);
3215       f.f += inc;
3216       f.f &= ~(inc - 1);
3217     }
3218 
3219     // Check long double overflow
3220     if (!has_implicit_bit<Float>()) {
3221       const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
3222       if ((f.f & implicit_bit) == implicit_bit) {
3223         f.f >>= 4;
3224         f.e += 4;
3225       }
3226     }
3227 
3228     print_xdigits = precision;
3229   }
3230 
3231   char xdigits[num_bits<carrier_uint>() / 4];
3232   detail::fill_n(xdigits, sizeof(xdigits), '0');
3233   format_uint<4>(xdigits, f.f, num_xdigits, specs.upper);
3234 
3235   // Remove zero tail
3236   while (print_xdigits > 0 && xdigits[print_xdigits] == '0') --print_xdigits;
3237 
3238   buf.push_back('0');
3239   buf.push_back(specs.upper ? 'X' : 'x');
3240   buf.push_back(xdigits[0]);
3241   if (specs.showpoint || print_xdigits > 0 || print_xdigits < precision)
3242     buf.push_back('.');
3243   buf.append(xdigits + 1, xdigits + 1 + print_xdigits);
3244   for (; print_xdigits < precision; ++print_xdigits) buf.push_back('0');
3245 
3246   buf.push_back(specs.upper ? 'P' : 'p');
3247 
3248   uint32_t abs_e;
3249   if (f.e < 0) {
3250     buf.push_back('-');
3251     abs_e = static_cast<uint32_t>(-f.e);
3252   } else {
3253     buf.push_back('+');
3254     abs_e = static_cast<uint32_t>(f.e);
3255   }
3256   format_decimal<char>(appender(buf), abs_e, detail::count_digits(abs_e));
3257 }
3258 
3259 template <typename Float, FMT_ENABLE_IF(is_double_double<Float>::value)>
3260 FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
3261                                      float_specs specs, buffer<char>& buf) {
3262   format_hexfloat(static_cast<double>(value), precision, specs, buf);
3263 }
3264 
3265 constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t {
3266   // For checking rounding thresholds.
3267   // The kth entry is chosen to be the smallest integer such that the
3268   // upper 32-bits of 10^(k+1) times it is strictly bigger than 5 * 10^k.
3269   // It is equal to ceil(2^31 + 2^32/10^(k + 1)).
3270   // These are stored in a string literal because we cannot have static arrays
3271   // in constexpr functions and non-static ones are poorly optimized.
3272   return U"\x9999999a\x828f5c29\x80418938\x80068db9\x8000a7c6\x800010c7"
3273          U"\x800001ae\x8000002b"[index];
3274 }
3275 
3276 template <typename Float>
3277 FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs,
3278                                   buffer<char>& buf) -> int {
3279   // float is passed as double to reduce the number of instantiations.
3280   static_assert(!std::is_same<Float, float>::value, "");
3281   FMT_ASSERT(value >= 0, "value is negative");
3282   auto converted_value = convert_float(value);
3283 
3284   const bool fixed = specs.format == float_format::fixed;
3285   if (value <= 0) {  // <= instead of == to silence a warning.
3286     if (precision <= 0 || !fixed) {
3287       buf.push_back('0');
3288       return 0;
3289     }
3290     buf.try_resize(to_unsigned(precision));
3291     fill_n(buf.data(), precision, '0');
3292     return -precision;
3293   }
3294 
3295   int exp = 0;
3296   bool use_dragon = true;
3297   unsigned dragon_flags = 0;
3298   if (!is_fast_float<Float>() || is_constant_evaluated()) {
3299     const auto inv_log2_10 = 0.3010299956639812;  // 1 / log2(10)
3300     using info = dragonbox::float_info<decltype(converted_value)>;
3301     const auto f = basic_fp<typename info::carrier_uint>(converted_value);
3302     // Compute exp, an approximate power of 10, such that
3303     //   10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1).
3304     // This is based on log10(value) == log2(value) / log2(10) and approximation
3305     // of log2(value) by e + num_fraction_bits idea from double-conversion.
3306     auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10;
3307     exp = static_cast<int>(e);
3308     if (e > exp) ++exp;  // Compute ceil.
3309     dragon_flags = dragon::fixup;
3310   } else if (precision < 0) {
3311     // Use Dragonbox for the shortest format.
3312     if (specs.binary32) {
3313       auto dec = dragonbox::to_decimal(static_cast<float>(value));
3314       write<char>(buffer_appender<char>(buf), dec.significand);
3315       return dec.exponent;
3316     }
3317     auto dec = dragonbox::to_decimal(static_cast<double>(value));
3318     write<char>(buffer_appender<char>(buf), dec.significand);
3319     return dec.exponent;
3320   } else {
3321     // Extract significand bits and exponent bits.
3322     using info = dragonbox::float_info<double>;
3323     auto br = bit_cast<uint64_t>(static_cast<double>(value));
3324 
3325     const uint64_t significand_mask =
3326         (static_cast<uint64_t>(1) << num_significand_bits<double>()) - 1;
3327     uint64_t significand = (br & significand_mask);
3328     int exponent = static_cast<int>((br & exponent_mask<double>()) >>
3329                                     num_significand_bits<double>());
3330 
3331     if (exponent != 0) {  // Check if normal.
3332       exponent -= exponent_bias<double>() + num_significand_bits<double>();
3333       significand |=
3334           (static_cast<uint64_t>(1) << num_significand_bits<double>());
3335       significand <<= 1;
3336     } else {
3337       // Normalize subnormal inputs.
3338       FMT_ASSERT(significand != 0, "zeros should not appear here");
3339       int shift = countl_zero(significand);
3340       FMT_ASSERT(shift >= num_bits<uint64_t>() - num_significand_bits<double>(),
3341                  "");
3342       shift -= (num_bits<uint64_t>() - num_significand_bits<double>() - 2);
3343       exponent = (std::numeric_limits<double>::min_exponent -
3344                   num_significand_bits<double>()) -
3345                  shift;
3346       significand <<= shift;
3347     }
3348 
3349     // Compute the first several nonzero decimal significand digits.
3350     // We call the number we get the first segment.
3351     const int k = info::kappa - dragonbox::floor_log10_pow2(exponent);
3352     exp = -k;
3353     const int beta = exponent + dragonbox::floor_log2_pow10(k);
3354     uint64_t first_segment;
3355     bool has_more_segments;
3356     int digits_in_the_first_segment;
3357     {
3358       const auto r = dragonbox::umul192_upper128(
3359           significand << beta, dragonbox::get_cached_power(k));
3360       first_segment = r.high();
3361       has_more_segments = r.low() != 0;
3362 
3363       // The first segment can have 18 ~ 19 digits.
3364       if (first_segment >= 1000000000000000000ULL) {
3365         digits_in_the_first_segment = 19;
3366       } else {
3367         // When it is of 18-digits, we align it to 19-digits by adding a bogus
3368         // zero at the end.
3369         digits_in_the_first_segment = 18;
3370         first_segment *= 10;
3371       }
3372     }
3373 
3374     // Compute the actual number of decimal digits to print.
3375     if (fixed) adjust_precision(precision, exp + digits_in_the_first_segment);
3376 
3377     // Use Dragon4 only when there might be not enough digits in the first
3378     // segment.
3379     if (digits_in_the_first_segment > precision) {
3380       use_dragon = false;
3381 
3382       if (precision <= 0) {
3383         exp += digits_in_the_first_segment;
3384 
3385         if (precision < 0) {
3386           // Nothing to do, since all we have are just leading zeros.
3387           buf.try_resize(0);
3388         } else {
3389           // We may need to round-up.
3390           buf.try_resize(1);
3391           if ((first_segment | static_cast<uint64_t>(has_more_segments)) >
3392               5000000000000000000ULL) {
3393             buf[0] = '1';
3394           } else {
3395             buf[0] = '0';
3396           }
3397         }
3398       }  // precision <= 0
3399       else {
3400         exp += digits_in_the_first_segment - precision;
3401 
3402         // When precision > 0, we divide the first segment into three
3403         // subsegments, each with 9, 9, and 0 ~ 1 digits so that each fits
3404         // in 32-bits which usually allows faster calculation than in
3405         // 64-bits. Since some compiler (e.g. MSVC) doesn't know how to optimize
3406         // division-by-constant for large 64-bit divisors, we do it here
3407         // manually. The magic number 7922816251426433760 below is equal to
3408         // ceil(2^(64+32) / 10^10).
3409         const uint32_t first_subsegment = static_cast<uint32_t>(
3410             dragonbox::umul128_upper64(first_segment, 7922816251426433760ULL) >>
3411             32);
3412         const uint64_t second_third_subsegments =
3413             first_segment - first_subsegment * 10000000000ULL;
3414 
3415         uint64_t prod;
3416         uint32_t digits;
3417         bool should_round_up;
3418         int number_of_digits_to_print = precision > 9 ? 9 : precision;
3419 
3420         // Print a 9-digits subsegment, either the first or the second.
3421         auto print_subsegment = [&](uint32_t subsegment, char* buffer) {
3422           int number_of_digits_printed = 0;
3423 
3424           // If we want to print an odd number of digits from the subsegment,
3425           if ((number_of_digits_to_print & 1) != 0) {
3426             // Convert to 64-bit fixed-point fractional form with 1-digit
3427             // integer part. The magic number 720575941 is a good enough
3428             // approximation of 2^(32 + 24) / 10^8; see
3429             // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case
3430             // for details.
3431             prod = ((subsegment * static_cast<uint64_t>(720575941)) >> 24) + 1;
3432             digits = static_cast<uint32_t>(prod >> 32);
3433             *buffer = static_cast<char>('0' + digits);
3434             number_of_digits_printed++;
3435           }
3436           // If we want to print an even number of digits from the
3437           // first_subsegment,
3438           else {
3439             // Convert to 64-bit fixed-point fractional form with 2-digits
3440             // integer part. The magic number 450359963 is a good enough
3441             // approximation of 2^(32 + 20) / 10^7; see
3442             // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case
3443             // for details.
3444             prod = ((subsegment * static_cast<uint64_t>(450359963)) >> 20) + 1;
3445             digits = static_cast<uint32_t>(prod >> 32);
3446             copy2(buffer, digits2(digits));
3447             number_of_digits_printed += 2;
3448           }
3449 
3450           // Print all digit pairs.
3451           while (number_of_digits_printed < number_of_digits_to_print) {
3452             prod = static_cast<uint32_t>(prod) * static_cast<uint64_t>(100);
3453             digits = static_cast<uint32_t>(prod >> 32);
3454             copy2(buffer + number_of_digits_printed, digits2(digits));
3455             number_of_digits_printed += 2;
3456           }
3457         };
3458 
3459         // Print first subsegment.
3460         print_subsegment(first_subsegment, buf.data());
3461 
3462         // Perform rounding if the first subsegment is the last subsegment to
3463         // print.
3464         if (precision <= 9) {
3465           // Rounding inside the subsegment.
3466           // We round-up if:
3467           //  - either the fractional part is strictly larger than 1/2, or
3468           //  - the fractional part is exactly 1/2 and the last digit is odd.
3469           // We rely on the following observations:
3470           //  - If fractional_part >= threshold, then the fractional part is
3471           //    strictly larger than 1/2.
3472           //  - If the MSB of fractional_part is set, then the fractional part
3473           //    must be at least 1/2.
3474           //  - When the MSB of fractional_part is set, either
3475           //    second_third_subsegments being nonzero or has_more_segments
3476           //    being true means there are further digits not printed, so the
3477           //    fractional part is strictly larger than 1/2.
3478           if (precision < 9) {
3479             uint32_t fractional_part = static_cast<uint32_t>(prod);
3480             should_round_up =
3481                 fractional_part >= fractional_part_rounding_thresholds(
3482                                        8 - number_of_digits_to_print) ||
3483                 ((fractional_part >> 31) &
3484                  ((digits & 1) | (second_third_subsegments != 0) |
3485                   has_more_segments)) != 0;
3486           }
3487           // Rounding at the subsegment boundary.
3488           // In this case, the fractional part is at least 1/2 if and only if
3489           // second_third_subsegments >= 5000000000ULL, and is strictly larger
3490           // than 1/2 if we further have either second_third_subsegments >
3491           // 5000000000ULL or has_more_segments == true.
3492           else {
3493             should_round_up = second_third_subsegments > 5000000000ULL ||
3494                               (second_third_subsegments == 5000000000ULL &&
3495                                ((digits & 1) != 0 || has_more_segments));
3496           }
3497         }
3498         // Otherwise, print the second subsegment.
3499         else {
3500           // Compilers are not aware of how to leverage the maximum value of
3501           // second_third_subsegments to find out a better magic number which
3502           // allows us to eliminate an additional shift. 1844674407370955162 =
3503           // ceil(2^64/10) < ceil(2^64*(10^9/(10^10 - 1))).
3504           const uint32_t second_subsegment =
3505               static_cast<uint32_t>(dragonbox::umul128_upper64(
3506                   second_third_subsegments, 1844674407370955162ULL));
3507           const uint32_t third_subsegment =
3508               static_cast<uint32_t>(second_third_subsegments) -
3509               second_subsegment * 10;
3510 
3511           number_of_digits_to_print = precision - 9;
3512           print_subsegment(second_subsegment, buf.data() + 9);
3513 
3514           // Rounding inside the subsegment.
3515           if (precision < 18) {
3516             // The condition third_subsegment != 0 implies that the segment was
3517             // of 19 digits, so in this case the third segment should be
3518             // consisting of a genuine digit from the input.
3519             uint32_t fractional_part = static_cast<uint32_t>(prod);
3520             should_round_up =
3521                 fractional_part >= fractional_part_rounding_thresholds(
3522                                        8 - number_of_digits_to_print) ||
3523                 ((fractional_part >> 31) &
3524                  ((digits & 1) | (third_subsegment != 0) |
3525                   has_more_segments)) != 0;
3526           }
3527           // Rounding at the subsegment boundary.
3528           else {
3529             // In this case, the segment must be of 19 digits, thus
3530             // the third subsegment should be consisting of a genuine digit from
3531             // the input.
3532             should_round_up = third_subsegment > 5 ||
3533                               (third_subsegment == 5 &&
3534                                ((digits & 1) != 0 || has_more_segments));
3535           }
3536         }
3537 
3538         // Round-up if necessary.
3539         if (should_round_up) {
3540           ++buf[precision - 1];
3541           for (int i = precision - 1; i > 0 && buf[i] > '9'; --i) {
3542             buf[i] = '0';
3543             ++buf[i - 1];
3544           }
3545           if (buf[0] > '9') {
3546             buf[0] = '1';
3547             if (fixed)
3548               buf[precision++] = '0';
3549             else
3550               ++exp;
3551           }
3552         }
3553         buf.try_resize(to_unsigned(precision));
3554       }
3555     }  // if (digits_in_the_first_segment > precision)
3556     else {
3557       // Adjust the exponent for its use in Dragon4.
3558       exp += digits_in_the_first_segment - 1;
3559     }
3560   }
3561   if (use_dragon) {
3562     auto f = basic_fp<uint128_t>();
3563     bool is_predecessor_closer = specs.binary32
3564                                      ? f.assign(static_cast<float>(value))
3565                                      : f.assign(converted_value);
3566     if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer;
3567     if (fixed) dragon_flags |= dragon::fixed;
3568     // Limit precision to the maximum possible number of significant digits in
3569     // an IEEE754 double because we don't need to generate zeros.
3570     const int max_double_digits = 767;
3571     if (precision > max_double_digits) precision = max_double_digits;
3572     format_dragon(f, dragon_flags, precision, buf, exp);
3573   }
3574   if (!fixed && !specs.showpoint) {
3575     // Remove trailing zeros.
3576     auto num_digits = buf.size();
3577     while (num_digits > 0 && buf[num_digits - 1] == '0') {
3578       --num_digits;
3579       ++exp;
3580     }
3581     buf.try_resize(num_digits);
3582   }
3583   return exp;
3584 }
3585 template <typename Char, typename OutputIt, typename T>
3586 FMT_CONSTEXPR20 auto write_float(OutputIt out, T value,
3587                                  format_specs<Char> specs, locale_ref loc)
3588     -> OutputIt {
3589   float_specs fspecs = parse_float_type_spec(specs);
3590   fspecs.sign = specs.sign;
3591   if (detail::signbit(value)) {  // value < 0 is false for NaN so use signbit.
3592     fspecs.sign = sign::minus;
3593     value = -value;
3594   } else if (fspecs.sign == sign::minus) {
3595     fspecs.sign = sign::none;
3596   }
3597 
3598   if (!detail::isfinite(value))
3599     return write_nonfinite(out, detail::isnan(value), specs, fspecs);
3600 
3601   if (specs.align == align::numeric && fspecs.sign) {
3602     auto it = reserve(out, 1);
3603     *it++ = detail::sign<Char>(fspecs.sign);
3604     out = base_iterator(out, it);
3605     fspecs.sign = sign::none;
3606     if (specs.width != 0) --specs.width;
3607   }
3608 
3609   memory_buffer buffer;
3610   if (fspecs.format == float_format::hex) {
3611     if (fspecs.sign) buffer.push_back(detail::sign<char>(fspecs.sign));
3612     format_hexfloat(convert_float(value), specs.precision, fspecs, buffer);
3613     return write_bytes<align::right>(out, {buffer.data(), buffer.size()},
3614                                      specs);
3615   }
3616   int precision = specs.precision >= 0 || specs.type == presentation_type::none
3617                       ? specs.precision
3618                       : 6;
3619   if (fspecs.format == float_format::exp) {
3620     if (precision == max_value<int>())
3621       throw_format_error("number is too big");
3622     else
3623       ++precision;
3624   } else if (fspecs.format != float_format::fixed && precision == 0) {
3625     precision = 1;
3626   }
3627   if (const_check(std::is_same<T, float>())) fspecs.binary32 = true;
3628   int exp = format_float(convert_float(value), precision, fspecs, buffer);
3629   fspecs.precision = precision;
3630   auto f = big_decimal_fp{buffer.data(), static_cast<int>(buffer.size()), exp};
3631   return write_float(out, f, specs, fspecs, loc);
3632 }
3633 
3634 template <typename Char, typename OutputIt, typename T,
3635           FMT_ENABLE_IF(is_floating_point<T>::value)>
3636 FMT_CONSTEXPR20 auto write(OutputIt out, T value, format_specs<Char> specs,
3637                            locale_ref loc = {}) -> OutputIt {
3638   if (const_check(!is_supported_floating_point(value))) return out;
3639   return specs.localized && write_loc(out, value, specs, loc)
3640              ? out
3641              : write_float(out, value, specs, loc);
3642 }
3643 
3644 template <typename Char, typename OutputIt, typename T,
3645           FMT_ENABLE_IF(is_fast_float<T>::value)>
3646 FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt {
3647   if (is_constant_evaluated()) return write(out, value, format_specs<Char>());
3648   if (const_check(!is_supported_floating_point(value))) return out;
3649 
3650   auto fspecs = float_specs();
3651   if (detail::signbit(value)) {
3652     fspecs.sign = sign::minus;
3653     value = -value;
3654   }
3655 
3656   constexpr auto specs = format_specs<Char>();
3657   using floaty = conditional_t<std::is_same<T, long double>::value, double, T>;
3658   using floaty_uint = typename dragonbox::float_info<floaty>::carrier_uint;
3659   floaty_uint mask = exponent_mask<floaty>();
3660   if ((bit_cast<floaty_uint>(value) & mask) == mask)
3661     return write_nonfinite(out, std::isnan(value), specs, fspecs);
3662 
3663   auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
3664   return write_float(out, dec, specs, fspecs, {});
3665 }
3666 
3667 template <typename Char, typename OutputIt, typename T,
3668           FMT_ENABLE_IF(is_floating_point<T>::value &&
3669                         !is_fast_float<T>::value)>
3670 inline auto write(OutputIt out, T value) -> OutputIt {
3671   return write(out, value, format_specs<Char>());
3672 }
3673 
3674 template <typename Char, typename OutputIt>
3675 auto write(OutputIt out, monostate, format_specs<Char> = {}, locale_ref = {})
3676     -> OutputIt {
3677   FMT_ASSERT(false, "");
3678   return out;
3679 }
3680 
3681 template <typename Char, typename OutputIt>
3682 FMT_CONSTEXPR auto write(OutputIt out, basic_string_view<Char> value)
3683     -> OutputIt {
3684   auto it = reserve(out, value.size());
3685   it = copy_str_noinline<Char>(value.begin(), value.end(), it);
3686   return base_iterator(out, it);
3687 }
3688 
3689 template <typename Char, typename OutputIt, typename T,
3690           FMT_ENABLE_IF(is_string<T>::value)>
3691 constexpr auto write(OutputIt out, const T& value) -> OutputIt {
3692   return write<Char>(out, to_string_view(value));
3693 }
3694 
3695 // FMT_ENABLE_IF() condition separated to workaround an MSVC bug.
3696 template <
3697     typename Char, typename OutputIt, typename T,
3698     bool check =
3699         std::is_enum<T>::value && !std::is_same<T, Char>::value &&
3700         mapped_type_constant<T, basic_format_context<OutputIt, Char>>::value !=
3701             type::custom_type,
3702     FMT_ENABLE_IF(check)>
3703 FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt {
3704   return write<Char>(out, static_cast<underlying_t<T>>(value));
3705 }
3706 
3707 template <typename Char, typename OutputIt, typename T,
3708           FMT_ENABLE_IF(std::is_same<T, bool>::value)>
3709 FMT_CONSTEXPR auto write(OutputIt out, T value,
3710                          const format_specs<Char>& specs = {}, locale_ref = {})
3711     -> OutputIt {
3712   return specs.type != presentation_type::none &&
3713                  specs.type != presentation_type::string
3714              ? write(out, value ? 1 : 0, specs, {})
3715              : write_bytes(out, value ? "true" : "false", specs);
3716 }
3717 
3718 template <typename Char, typename OutputIt>
3719 FMT_CONSTEXPR auto write(OutputIt out, Char value) -> OutputIt {
3720   auto it = reserve(out, 1);
3721   *it++ = value;
3722   return base_iterator(out, it);
3723 }
3724 
3725 template <typename Char, typename OutputIt>
3726 FMT_CONSTEXPR_CHAR_TRAITS auto write(OutputIt out, const Char* value)
3727     -> OutputIt {
3728   if (value) return write(out, basic_string_view<Char>(value));
3729   throw_format_error("string pointer is null");
3730   return out;
3731 }
3732 
3733 template <typename Char, typename OutputIt, typename T,
3734           FMT_ENABLE_IF(std::is_same<T, void>::value)>
3735 auto write(OutputIt out, const T* value, const format_specs<Char>& specs = {},
3736            locale_ref = {}) -> OutputIt {
3737   return write_ptr<Char>(out, bit_cast<uintptr_t>(value), &specs);
3738 }
3739 
3740 // A write overload that handles implicit conversions.
3741 template <typename Char, typename OutputIt, typename T,
3742           typename Context = basic_format_context<OutputIt, Char>>
3743 FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> enable_if_t<
3744     std::is_class<T>::value && !is_string<T>::value &&
3745         !is_floating_point<T>::value && !std::is_same<T, Char>::value &&
3746         !std::is_same<T, remove_cvref_t<decltype(arg_mapper<Context>().map(
3747                              value))>>::value,
3748     OutputIt> {
3749   return write<Char>(out, arg_mapper<Context>().map(value));
3750 }
3751 
3752 template <typename Char, typename OutputIt, typename T,
3753           typename Context = basic_format_context<OutputIt, Char>>
3754 FMT_CONSTEXPR auto write(OutputIt out, const T& value)
3755     -> enable_if_t<mapped_type_constant<T, Context>::value == type::custom_type,
3756                    OutputIt> {
3757   auto formatter = typename Context::template formatter_type<T>();
3758   auto parse_ctx = typename Context::parse_context_type({});
3759   formatter.parse(parse_ctx);
3760   auto ctx = Context(out, {}, {});
3761   return formatter.format(value, ctx);
3762 }
3763 
3764 // An argument visitor that formats the argument and writes it via the output
3765 // iterator. It's a class and not a generic lambda for compatibility with C++11.
3766 template <typename Char> struct default_arg_formatter {
3767   using iterator = buffer_appender<Char>;
3768   using context = buffer_context<Char>;
3769 
3770   iterator out;
3771   basic_format_args<context> args;
3772   locale_ref loc;
3773 
3774   template <typename T> auto operator()(T value) -> iterator {
3775     return write<Char>(out, value);
3776   }
3777   auto operator()(typename basic_format_arg<context>::handle h) -> iterator {
3778     basic_format_parse_context<Char> parse_ctx({});
3779     context format_ctx(out, args, loc);
3780     h.format(parse_ctx, format_ctx);
3781     return format_ctx.out();
3782   }
3783 };
3784 
3785 template <typename Char> struct arg_formatter {
3786   using iterator = buffer_appender<Char>;
3787   using context = buffer_context<Char>;
3788 
3789   iterator out;
3790   const format_specs<Char>& specs;
3791   locale_ref locale;
3792 
3793   template <typename T>
3794   FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator {
3795     return detail::write(out, value, specs, locale);
3796   }
3797   auto operator()(typename basic_format_arg<context>::handle) -> iterator {
3798     // User-defined types are handled separately because they require access
3799     // to the parse context.
3800     return out;
3801   }
3802 };
3803 
3804 struct width_checker {
3805   template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
3806   FMT_CONSTEXPR auto operator()(T value) -> unsigned long long {
3807     if (is_negative(value)) throw_format_error("negative width");
3808     return static_cast<unsigned long long>(value);
3809   }
3810 
3811   template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
3812   FMT_CONSTEXPR auto operator()(T) -> unsigned long long {
3813     throw_format_error("width is not integer");
3814     return 0;
3815   }
3816 };
3817 
3818 struct precision_checker {
3819   template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
3820   FMT_CONSTEXPR auto operator()(T value) -> unsigned long long {
3821     if (is_negative(value)) throw_format_error("negative precision");
3822     return static_cast<unsigned long long>(value);
3823   }
3824 
3825   template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
3826   FMT_CONSTEXPR auto operator()(T) -> unsigned long long {
3827     throw_format_error("precision is not integer");
3828     return 0;
3829   }
3830 };
3831 
3832 template <typename Handler, typename FormatArg>
3833 FMT_CONSTEXPR auto get_dynamic_spec(FormatArg arg) -> int {
3834   unsigned long long value = visit_format_arg(Handler(), arg);
3835   if (value > to_unsigned(max_value<int>()))
3836     throw_format_error("number is too big");
3837   return static_cast<int>(value);
3838 }
3839 
3840 template <typename Context, typename ID>
3841 FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> decltype(ctx.arg(id)) {
3842   auto arg = ctx.arg(id);
3843   if (!arg) ctx.on_error("argument not found");
3844   return arg;
3845 }
3846 
3847 template <typename Handler, typename Context>
3848 FMT_CONSTEXPR void handle_dynamic_spec(int& value,
3849                                        arg_ref<typename Context::char_type> ref,
3850                                        Context& ctx) {
3851   switch (ref.kind) {
3852   case arg_id_kind::none:
3853     break;
3854   case arg_id_kind::index:
3855     value = detail::get_dynamic_spec<Handler>(get_arg(ctx, ref.val.index));
3856     break;
3857   case arg_id_kind::name:
3858     value = detail::get_dynamic_spec<Handler>(get_arg(ctx, ref.val.name));
3859     break;
3860   }
3861 }
3862 
3863 #if FMT_USE_USER_DEFINED_LITERALS
3864 #  if FMT_USE_NONTYPE_TEMPLATE_ARGS
3865 template <typename T, typename Char, size_t N,
3866           fmt::detail_exported::fixed_string<Char, N> Str>
3867 struct statically_named_arg : view {
3868   static constexpr auto name = Str.data;
3869 
3870   const T& value;
3871   statically_named_arg(const T& v) : value(v) {}
3872 };
3873 
3874 template <typename T, typename Char, size_t N,
3875           fmt::detail_exported::fixed_string<Char, N> Str>
3876 struct is_named_arg<statically_named_arg<T, Char, N, Str>> : std::true_type {};
3877 
3878 template <typename T, typename Char, size_t N,
3879           fmt::detail_exported::fixed_string<Char, N> Str>
3880 struct is_statically_named_arg<statically_named_arg<T, Char, N, Str>>
3881     : std::true_type {};
3882 
3883 template <typename Char, size_t N,
3884           fmt::detail_exported::fixed_string<Char, N> Str>
3885 struct udl_arg {
3886   template <typename T> auto operator=(T&& value) const {
3887     return statically_named_arg<T, Char, N, Str>(std::forward<T>(value));
3888   }
3889 };
3890 #  else
3891 template <typename Char> struct udl_arg {
3892   const Char* str;
3893 
3894   template <typename T> auto operator=(T&& value) const -> named_arg<Char, T> {
3895     return {str, std::forward<T>(value)};
3896   }
3897 };
3898 #  endif
3899 #endif  // FMT_USE_USER_DEFINED_LITERALS
3900 
3901 template <typename Locale, typename Char>
3902 auto vformat(const Locale& loc, basic_string_view<Char> fmt,
3903              basic_format_args<buffer_context<type_identity_t<Char>>> args)
3904     -> std::basic_string<Char> {
3905   auto buf = basic_memory_buffer<Char>();
3906   detail::vformat_to(buf, fmt, args, detail::locale_ref(loc));
3907   return {buf.data(), buf.size()};
3908 }
3909 
3910 using format_func = void (*)(detail::buffer<char>&, int, const char*);
3911 
3912 FMT_API void format_error_code(buffer<char>& out, int error_code,
3913                                string_view message) noexcept;
3914 
3915 FMT_API void report_error(format_func func, int error_code,
3916                           const char* message) noexcept;
3917 }  // namespace detail
3918 
3919 FMT_API auto vsystem_error(int error_code, string_view format_str,
3920                            format_args args) -> std::system_error;
3921 
3922 /**
3923   \rst
3924   Constructs :class:`std::system_error` with a message formatted with
3925   ``fmt::format(fmt, args...)``.
3926   *error_code* is a system error code as given by ``errno``.
3927 
3928   **Example**::
3929 
3930     // This throws std::system_error with the description
3931     //   cannot open file 'madeup': No such file or directory
3932     // or similar (system message may vary).
3933     const char* filename = "madeup";
3934     std::FILE* file = std::fopen(filename, "r");
3935     if (!file)
3936       throw fmt::system_error(errno, "cannot open file '{}'", filename);
3937   \endrst
3938  */
3939 template <typename... T>
3940 auto system_error(int error_code, format_string<T...> fmt, T&&... args)
3941     -> std::system_error {
3942   return vsystem_error(error_code, fmt, fmt::make_format_args(args...));
3943 }
3944 
3945 /**
3946   \rst
3947   Formats an error message for an error returned by an operating system or a
3948   language runtime, for example a file opening error, and writes it to *out*.
3949   The format is the same as the one used by ``std::system_error(ec, message)``
3950   where ``ec`` is ``std::error_code(error_code, std::generic_category()})``.
3951   It is implementation-defined but normally looks like:
3952 
3953   .. parsed-literal::
3954      *<message>*: *<system-message>*
3955 
3956   where *<message>* is the passed message and *<system-message>* is the system
3957   message corresponding to the error code.
3958   *error_code* is a system error code as given by ``errno``.
3959   \endrst
3960  */
3961 FMT_API void format_system_error(detail::buffer<char>& out, int error_code,
3962                                  const char* message) noexcept;
3963 
3964 // Reports a system error without throwing an exception.
3965 // Can be used to report errors from destructors.
3966 FMT_API void report_system_error(int error_code, const char* message) noexcept;
3967 
3968 /** Fast integer formatter. */
3969 class format_int {
3970  private:
3971   // Buffer should be large enough to hold all digits (digits10 + 1),
3972   // a sign and a null character.
3973   enum { buffer_size = std::numeric_limits<unsigned long long>::digits10 + 3 };
3974   mutable char buffer_[buffer_size];
3975   char* str_;
3976 
3977   template <typename UInt> auto format_unsigned(UInt value) -> char* {
3978     auto n = static_cast<detail::uint32_or_64_or_128_t<UInt>>(value);
3979     return detail::format_decimal(buffer_, n, buffer_size - 1).begin;
3980   }
3981 
3982   template <typename Int> auto format_signed(Int value) -> char* {
3983     auto abs_value = static_cast<detail::uint32_or_64_or_128_t<Int>>(value);
3984     bool negative = value < 0;
3985     if (negative) abs_value = 0 - abs_value;
3986     auto begin = format_unsigned(abs_value);
3987     if (negative) *--begin = '-';
3988     return begin;
3989   }
3990 
3991  public:
3992   explicit format_int(int value) : str_(format_signed(value)) {}
3993   explicit format_int(long value) : str_(format_signed(value)) {}
3994   explicit format_int(long long value) : str_(format_signed(value)) {}
3995   explicit format_int(unsigned value) : str_(format_unsigned(value)) {}
3996   explicit format_int(unsigned long value) : str_(format_unsigned(value)) {}
3997   explicit format_int(unsigned long long value)
3998       : str_(format_unsigned(value)) {}
3999 
4000   /** Returns the number of characters written to the output buffer. */
4001   auto size() const -> size_t {
4002     return detail::to_unsigned(buffer_ - str_ + buffer_size - 1);
4003   }
4004 
4005   /**
4006     Returns a pointer to the output buffer content. No terminating null
4007     character is appended.
4008    */
4009   auto data() const -> const char* { return str_; }
4010 
4011   /**
4012     Returns a pointer to the output buffer content with terminating null
4013     character appended.
4014    */
4015   auto c_str() const -> const char* {
4016     buffer_[buffer_size - 1] = '\0';
4017     return str_;
4018   }
4019 
4020   /**
4021     \rst
4022     Returns the content of the output buffer as an ``std::string``.
4023     \endrst
4024    */
4025   auto str() const -> std::string { return std::string(str_, size()); }
4026 };
4027 
4028 template <typename T, typename Char>
4029 struct formatter<T, Char, enable_if_t<detail::has_format_as<T>::value>>
4030     : formatter<detail::format_as_t<T>, Char> {
4031   template <typename FormatContext>
4032   auto format(const T& value, FormatContext& ctx) const -> decltype(ctx.out()) {
4033     using base = formatter<detail::format_as_t<T>, Char>;
4034     return base::format(format_as(value), ctx);
4035   }
4036 };
4037 
4038 #define FMT_FORMAT_AS(Type, Base) \
4039   template <typename Char>        \
4040   struct formatter<Type, Char> : formatter<Base, Char> {}
4041 
4042 FMT_FORMAT_AS(signed char, int);
4043 FMT_FORMAT_AS(unsigned char, unsigned);
4044 FMT_FORMAT_AS(short, int);
4045 FMT_FORMAT_AS(unsigned short, unsigned);
4046 FMT_FORMAT_AS(long, detail::long_type);
4047 FMT_FORMAT_AS(unsigned long, detail::ulong_type);
4048 FMT_FORMAT_AS(Char*, const Char*);
4049 FMT_FORMAT_AS(std::basic_string<Char>, basic_string_view<Char>);
4050 FMT_FORMAT_AS(std::nullptr_t, const void*);
4051 FMT_FORMAT_AS(detail::std_string_view<Char>, basic_string_view<Char>);
4052 FMT_FORMAT_AS(void*, const void*);
4053 
4054 template <typename Char, size_t N>
4055 struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> {};
4056 
4057 /**
4058   \rst
4059   Converts ``p`` to ``const void*`` for pointer formatting.
4060 
4061   **Example**::
4062 
4063     auto s = fmt::format("{}", fmt::ptr(p));
4064   \endrst
4065  */
4066 template <typename T> auto ptr(T p) -> const void* {
4067   static_assert(std::is_pointer<T>::value, "");
4068   return detail::bit_cast<const void*>(p);
4069 }
4070 template <typename T, typename Deleter>
4071 auto ptr(const std::unique_ptr<T, Deleter>& p) -> const void* {
4072   return p.get();
4073 }
4074 template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* {
4075   return p.get();
4076 }
4077 
4078 /**
4079   \rst
4080   Converts ``e`` to the underlying type.
4081 
4082   **Example**::
4083 
4084     enum class color { red, green, blue };
4085     auto s = fmt::format("{}", fmt::underlying(color::red));
4086   \endrst
4087  */
4088 template <typename Enum>
4089 constexpr auto underlying(Enum e) noexcept -> underlying_t<Enum> {
4090   return static_cast<underlying_t<Enum>>(e);
4091 }
4092 
4093 namespace enums {
4094 template <typename Enum, FMT_ENABLE_IF(std::is_enum<Enum>::value)>
4095 constexpr auto format_as(Enum e) noexcept -> underlying_t<Enum> {
4096   return static_cast<underlying_t<Enum>>(e);
4097 }
4098 }  // namespace enums
4099 
4100 class bytes {
4101  private:
4102   string_view data_;
4103   friend struct formatter<bytes>;
4104 
4105  public:
4106   explicit bytes(string_view data) : data_(data) {}
4107 };
4108 
4109 template <> struct formatter<bytes> {
4110  private:
4111   detail::dynamic_format_specs<> specs_;
4112 
4113  public:
4114   template <typename ParseContext>
4115   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const char* {
4116     return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
4117                               detail::type::string_type);
4118   }
4119 
4120   template <typename FormatContext>
4121   auto format(bytes b, FormatContext& ctx) -> decltype(ctx.out()) {
4122     detail::handle_dynamic_spec<detail::width_checker>(specs_.width,
4123                                                        specs_.width_ref, ctx);
4124     detail::handle_dynamic_spec<detail::precision_checker>(
4125         specs_.precision, specs_.precision_ref, ctx);
4126     return detail::write_bytes(ctx.out(), b.data_, specs_);
4127   }
4128 };
4129 
4130 // group_digits_view is not derived from view because it copies the argument.
4131 template <typename T> struct group_digits_view {
4132   T value;
4133 };
4134 
4135 /**
4136   \rst
4137   Returns a view that formats an integer value using ',' as a locale-independent
4138   thousands separator.
4139 
4140   **Example**::
4141 
4142     fmt::print("{}", fmt::group_digits(12345));
4143     // Output: "12,345"
4144   \endrst
4145  */
4146 template <typename T> auto group_digits(T value) -> group_digits_view<T> {
4147   return {value};
4148 }
4149 
4150 template <typename T> struct formatter<group_digits_view<T>> : formatter<T> {
4151  private:
4152   detail::dynamic_format_specs<> specs_;
4153 
4154  public:
4155   template <typename ParseContext>
4156   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const char* {
4157     return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
4158                               detail::type::int_type);
4159   }
4160 
4161   template <typename FormatContext>
4162   auto format(group_digits_view<T> t, FormatContext& ctx)
4163       -> decltype(ctx.out()) {
4164     detail::handle_dynamic_spec<detail::width_checker>(specs_.width,
4165                                                        specs_.width_ref, ctx);
4166     detail::handle_dynamic_spec<detail::precision_checker>(
4167         specs_.precision, specs_.precision_ref, ctx);
4168     return detail::write_int(
4169         ctx.out(), static_cast<detail::uint64_or_128_t<T>>(t.value), 0, specs_,
4170         detail::digit_grouping<char>("\3", ","));
4171   }
4172 };
4173 
4174 template <typename T> struct nested_view {
4175   const formatter<T>* fmt;
4176   const T* value;
4177 };
4178 
4179 template <typename T> struct formatter<nested_view<T>> {
4180   FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> const char* {
4181     return ctx.begin();
4182   }
4183   auto format(nested_view<T> view, format_context& ctx) const
4184       -> decltype(ctx.out()) {
4185     return view.fmt->format(*view.value, ctx);
4186   }
4187 };
4188 
4189 template <typename T> struct nested_formatter {
4190  private:
4191   int width_;
4192   detail::fill_t<char> fill_;
4193   align_t align_ : 4;
4194   formatter<T> formatter_;
4195 
4196  public:
4197   constexpr nested_formatter() : width_(0), align_(align_t::none) {}
4198 
4199   FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> const char* {
4200     auto specs = detail::dynamic_format_specs<char>();
4201     auto it = parse_format_specs(ctx.begin(), ctx.end(), specs, ctx,
4202                                  detail::type::none_type);
4203     width_ = specs.width;
4204     fill_ = specs.fill;
4205     align_ = specs.align;
4206     ctx.advance_to(it);
4207     return formatter_.parse(ctx);
4208   }
4209 
4210   template <typename F>
4211   auto write_padded(format_context& ctx, F write) const -> decltype(ctx.out()) {
4212     if (width_ == 0) return write(ctx.out());
4213     auto buf = memory_buffer();
4214     write(std::back_inserter(buf));
4215     auto specs = format_specs<>();
4216     specs.width = width_;
4217     specs.fill = fill_;
4218     specs.align = align_;
4219     return detail::write(ctx.out(), string_view(buf.data(), buf.size()), specs);
4220   }
4221 
4222   auto nested(const T& value) const -> nested_view<T> {
4223     return nested_view<T>{&formatter_, &value};
4224   }
4225 };
4226 
4227 // DEPRECATED! join_view will be moved to ranges.h.
4228 template <typename It, typename Sentinel, typename Char = char>
4229 struct join_view : detail::view {
4230   It begin;
4231   Sentinel end;
4232   basic_string_view<Char> sep;
4233 
4234   join_view(It b, Sentinel e, basic_string_view<Char> s)
4235       : begin(b), end(e), sep(s) {}
4236 };
4237 
4238 template <typename It, typename Sentinel, typename Char>
4239 struct formatter<join_view<It, Sentinel, Char>, Char> {
4240  private:
4241   using value_type =
4242 #ifdef __cpp_lib_ranges
4243       std::iter_value_t<It>;
4244 #else
4245       typename std::iterator_traits<It>::value_type;
4246 #endif
4247   formatter<remove_cvref_t<value_type>, Char> value_formatter_;
4248 
4249  public:
4250   template <typename ParseContext>
4251   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* {
4252     return value_formatter_.parse(ctx);
4253   }
4254 
4255   template <typename FormatContext>
4256   auto format(const join_view<It, Sentinel, Char>& value,
4257               FormatContext& ctx) const -> decltype(ctx.out()) {
4258     auto it = value.begin;
4259     auto out = ctx.out();
4260     if (it != value.end) {
4261       out = value_formatter_.format(*it, ctx);
4262       ++it;
4263       while (it != value.end) {
4264         out = detail::copy_str<Char>(value.sep.begin(), value.sep.end(), out);
4265         ctx.advance_to(out);
4266         out = value_formatter_.format(*it, ctx);
4267         ++it;
4268       }
4269     }
4270     return out;
4271   }
4272 };
4273 
4274 /**
4275   Returns a view that formats the iterator range `[begin, end)` with elements
4276   separated by `sep`.
4277  */
4278 template <typename It, typename Sentinel>
4279 auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
4280   return {begin, end, sep};
4281 }
4282 
4283 /**
4284   \rst
4285   Returns a view that formats `range` with elements separated by `sep`.
4286 
4287   **Example**::
4288 
4289     std::vector<int> v = {1, 2, 3};
4290     fmt::print("{}", fmt::join(v, ", "));
4291     // Output: "1, 2, 3"
4292 
4293   ``fmt::join`` applies passed format specifiers to the range elements::
4294 
4295     fmt::print("{:02}", fmt::join(v, ", "));
4296     // Output: "01, 02, 03"
4297   \endrst
4298  */
4299 template <typename Range>
4300 auto join(Range&& range, string_view sep)
4301     -> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>> {
4302   return join(std::begin(range), std::end(range), sep);
4303 }
4304 
4305 /**
4306   \rst
4307   Converts *value* to ``std::string`` using the default format for type *T*.
4308 
4309   **Example**::
4310 
4311     #include <fmt/format.h>
4312 
4313     std::string answer = fmt::to_string(42);
4314   \endrst
4315  */
4316 template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value &&
4317                                     !detail::has_format_as<T>::value)>
4318 inline auto to_string(const T& value) -> std::string {
4319   auto buffer = memory_buffer();
4320   detail::write<char>(appender(buffer), value);
4321   return {buffer.data(), buffer.size()};
4322 }
4323 
4324 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
4325 FMT_NODISCARD inline auto to_string(T value) -> std::string {
4326   // The buffer should be large enough to store the number including the sign
4327   // or "false" for bool.
4328   constexpr int max_size = detail::digits10<T>() + 2;
4329   char buffer[max_size > 5 ? static_cast<unsigned>(max_size) : 5];
4330   char* begin = buffer;
4331   return std::string(begin, detail::write<char>(begin, value));
4332 }
4333 
4334 template <typename Char, size_t SIZE>
4335 FMT_NODISCARD auto to_string(const basic_memory_buffer<Char, SIZE>& buf)
4336     -> std::basic_string<Char> {
4337   auto size = buf.size();
4338   detail::assume(size < std::basic_string<Char>().max_size());
4339   return std::basic_string<Char>(buf.data(), size);
4340 }
4341 
4342 template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value &&
4343                                     detail::has_format_as<T>::value)>
4344 inline auto to_string(const T& value) -> std::string {
4345   return to_string(format_as(value));
4346 }
4347 
4348 FMT_END_EXPORT
4349 
4350 namespace detail {
4351 
4352 template <typename Char>
4353 void vformat_to(buffer<Char>& buf, basic_string_view<Char> fmt,
4354                 typename vformat_args<Char>::type args, locale_ref loc) {
4355   auto out = buffer_appender<Char>(buf);
4356   if (fmt.size() == 2 && equal2(fmt.data(), "{}")) {
4357     auto arg = args.get(0);
4358     if (!arg) throw_format_error("argument not found");
4359     visit_format_arg(default_arg_formatter<Char>{out, args, loc}, arg);
4360     return;
4361   }
4362 
4363   struct format_handler : error_handler {
4364     basic_format_parse_context<Char> parse_context;
4365     buffer_context<Char> context;
4366 
4367     format_handler(buffer_appender<Char> p_out, basic_string_view<Char> str,
4368                    basic_format_args<buffer_context<Char>> p_args,
4369                    locale_ref p_loc)
4370         : parse_context(str), context(p_out, p_args, p_loc) {}
4371 
4372     void on_text(const Char* begin, const Char* end) {
4373       auto text = basic_string_view<Char>(begin, to_unsigned(end - begin));
4374       context.advance_to(write<Char>(context.out(), text));
4375     }
4376 
4377     FMT_CONSTEXPR auto on_arg_id() -> int {
4378       return parse_context.next_arg_id();
4379     }
4380     FMT_CONSTEXPR auto on_arg_id(int id) -> int {
4381       return parse_context.check_arg_id(id), id;
4382     }
4383     FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
4384       int arg_id = context.arg_id(id);
4385       if (arg_id < 0) throw_format_error("argument not found");
4386       return arg_id;
4387     }
4388 
4389     FMT_INLINE void on_replacement_field(int id, const Char*) {
4390       auto arg = get_arg(context, id);
4391       context.advance_to(visit_format_arg(
4392           default_arg_formatter<Char>{context.out(), context.args(),
4393                                       context.locale()},
4394           arg));
4395     }
4396 
4397     auto on_format_specs(int id, const Char* begin, const Char* end)
4398         -> const Char* {
4399       auto arg = get_arg(context, id);
4400       // Not using a visitor for custom types gives better codegen.
4401       if (arg.format_custom(begin, parse_context, context))
4402         return parse_context.begin();
4403       auto specs = detail::dynamic_format_specs<Char>();
4404       begin = parse_format_specs(begin, end, specs, parse_context, arg.type());
4405       detail::handle_dynamic_spec<detail::width_checker>(
4406           specs.width, specs.width_ref, context);
4407       detail::handle_dynamic_spec<detail::precision_checker>(
4408           specs.precision, specs.precision_ref, context);
4409       if (begin == end || *begin != '}')
4410         throw_format_error("missing '}' in format string");
4411       auto f = arg_formatter<Char>{context.out(), specs, context.locale()};
4412       context.advance_to(visit_format_arg(f, arg));
4413       return begin;
4414     }
4415   };
4416   detail::parse_format_string<false>(fmt, format_handler(out, fmt, args, loc));
4417 }
4418 
4419 FMT_BEGIN_EXPORT
4420 
4421 #ifndef FMT_HEADER_ONLY
4422 extern template FMT_API void vformat_to(buffer<char>&, string_view,
4423                                         typename vformat_args<>::type,
4424                                         locale_ref);
4425 extern template FMT_API auto thousands_sep_impl<char>(locale_ref)
4426     -> thousands_sep_result<char>;
4427 extern template FMT_API auto thousands_sep_impl<wchar_t>(locale_ref)
4428     -> thousands_sep_result<wchar_t>;
4429 extern template FMT_API auto decimal_point_impl(locale_ref) -> char;
4430 extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
4431 #endif  // FMT_HEADER_ONLY
4432 
4433 }  // namespace detail
4434 
4435 #if FMT_USE_USER_DEFINED_LITERALS
4436 inline namespace literals {
4437 /**
4438   \rst
4439   User-defined literal equivalent of :func:`fmt::arg`.
4440 
4441   **Example**::
4442 
4443     using namespace fmt::literals;
4444     fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23);
4445   \endrst
4446  */
4447 #  if FMT_USE_NONTYPE_TEMPLATE_ARGS
4448 template <detail_exported::fixed_string Str> constexpr auto operator""_a() {
4449   using char_t = remove_cvref_t<decltype(Str.data[0])>;
4450   return detail::udl_arg<char_t, sizeof(Str.data) / sizeof(char_t), Str>();
4451 }
4452 #  else
4453 constexpr auto operator""_a(const char* s, size_t) -> detail::udl_arg<char> {
4454   return {s};
4455 }
4456 #  endif
4457 }  // namespace literals
4458 #endif  // FMT_USE_USER_DEFINED_LITERALS
4459 
4460 template <typename Locale, FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
4461 inline auto vformat(const Locale& loc, string_view fmt, format_args args)
4462     -> std::string {
4463   return detail::vformat(loc, fmt, args);
4464 }
4465 
4466 template <typename Locale, typename... T,
4467           FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
4468 inline auto format(const Locale& loc, format_string<T...> fmt, T&&... args)
4469     -> std::string {
4470   return fmt::vformat(loc, string_view(fmt), fmt::make_format_args(args...));
4471 }
4472 
4473 template <typename OutputIt, typename Locale,
4474           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value&&
4475                             detail::is_locale<Locale>::value)>
4476 auto vformat_to(OutputIt out, const Locale& loc, string_view fmt,
4477                 format_args args) -> OutputIt {
4478   using detail::get_buffer;
4479   auto&& buf = get_buffer<char>(out);
4480   detail::vformat_to(buf, fmt, args, detail::locale_ref(loc));
4481   return detail::get_iterator(buf, out);
4482 }
4483 
4484 template <typename OutputIt, typename Locale, typename... T,
4485           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value&&
4486                             detail::is_locale<Locale>::value)>
4487 FMT_INLINE auto format_to(OutputIt out, const Locale& loc,
4488                           format_string<T...> fmt, T&&... args) -> OutputIt {
4489   return vformat_to(out, loc, fmt, fmt::make_format_args(args...));
4490 }
4491 
4492 template <typename Locale, typename... T,
4493           FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
4494 FMT_NODISCARD FMT_INLINE auto formatted_size(const Locale& loc,
4495                                              format_string<T...> fmt,
4496                                              T&&... args) -> size_t {
4497   auto buf = detail::counting_buffer<>();
4498   detail::vformat_to<char>(buf, fmt, fmt::make_format_args(args...),
4499                            detail::locale_ref(loc));
4500   return buf.count();
4501 }
4502 
4503 FMT_END_EXPORT
4504 
4505 template <typename T, typename Char>
4506 template <typename FormatContext>
4507 FMT_CONSTEXPR FMT_INLINE auto
4508 formatter<T, Char,
4509           enable_if_t<detail::type_constant<T, Char>::value !=
4510                       detail::type::custom_type>>::format(const T& val,
4511                                                           FormatContext& ctx)
4512     const -> decltype(ctx.out()) {
4513   if (specs_.width_ref.kind == detail::arg_id_kind::none &&
4514       specs_.precision_ref.kind == detail::arg_id_kind::none) {
4515     return detail::write<Char>(ctx.out(), val, specs_, ctx.locale());
4516   }
4517   auto specs = specs_;
4518   detail::handle_dynamic_spec<detail::width_checker>(specs.width,
4519                                                      specs.width_ref, ctx);
4520   detail::handle_dynamic_spec<detail::precision_checker>(
4521       specs.precision, specs.precision_ref, ctx);
4522   return detail::write<Char>(ctx.out(), val, specs, ctx.locale());
4523 }
4524 
4525 FMT_END_NAMESPACE
4526 
4527 #ifdef FMT_HEADER_ONLY
4528 #  define FMT_FUNC inline
4529 #  include "format-inl.h"
4530 #else
4531 #  define FMT_FUNC
4532 #endif
4533 
4534 #endif  // FMT_FORMAT_H_
4535