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