36 #ifndef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES 37 # define _LIBCPP_REMOVE_TRANSITIVE_INCLUDES 38 # define FMT_REMOVE_TRANSITIVE_INCLUDES 51 # if defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI) 57 # include <system_error> 60 # if FMT_HAS_INCLUDE(<bit>) && FMT_CPLUSPLUS > 201703L 65 # if FMT_HAS_INCLUDE(<string_view>) && \ 66 (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION)) 67 # include <string_view> 68 # define FMT_USE_STRING_VIEW 76 #if defined(FMT_USE_NONTYPE_TEMPLATE_ARGS) 78 #elif defined(__NVCOMPILER) 79 # define FMT_USE_NONTYPE_TEMPLATE_ARGS 0 80 #elif FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L 81 # define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 82 #elif defined(__cpp_nontype_template_args) && \ 83 __cpp_nontype_template_args >= 201911L 84 # define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 85 #elif FMT_CLANG_VERSION >= 1200 && FMT_CPLUSPLUS >= 202002L 86 # define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 88 # define FMT_USE_NONTYPE_TEMPLATE_ARGS 0 91 #if defined __cpp_inline_variables && __cpp_inline_variables >= 201606L 92 # define FMT_INLINE_VARIABLE inline 94 # define FMT_INLINE_VARIABLE 100 #elif defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || defined(_CPPRTTI) || \ 101 defined(__INTEL_RTTI__) || defined(__RTTI) 103 # define FMT_USE_RTTI 1 105 # define FMT_USE_RTTI 0 109 #if defined(FMT_LIB_EXPORT) || defined(FMT_SHARED) 110 # define FMT_SO_VISIBILITY(value) FMT_VISIBILITY(value) 112 # define FMT_SO_VISIBILITY(value) 115 #if FMT_GCC_VERSION || FMT_CLANG_VERSION 116 # define FMT_NOINLINE __attribute__((noinline)) 118 # define FMT_NOINLINE 121 #ifdef FMT_DEPRECATED 123 #elif FMT_HAS_CPP14_ATTRIBUTE(deprecated) 124 # define FMT_DEPRECATED [[deprecated]] 126 # define FMT_DEPRECATED 130 #if !FMT_USE_CONSTEVAL 131 # define FMT_USE_CONSTEXPR_STRING 0 132 #elif defined(__cpp_lib_constexpr_string) && \ 133 __cpp_lib_constexpr_string >= 201907L 134 # if FMT_CLANG_VERSION && FMT_GLIBCXX_RELEASE 137 # if FMT_GLIBCXX_RELEASE < 13 138 # define FMT_USE_CONSTEXPR_STRING 0 139 # elif FMT_GLIBCXX_RELEASE == 13 && __GLIBCXX__ < 20240521 140 # define FMT_USE_CONSTEXPR_STRING 0 142 # define FMT_USE_CONSTEXPR_STRING 1 145 # define FMT_USE_CONSTEXPR_STRING 1 148 # define FMT_USE_CONSTEXPR_STRING 0 150 #if FMT_USE_CONSTEXPR_STRING 151 # define FMT_CONSTEXPR_STRING constexpr 153 # define FMT_CONSTEXPR_STRING 158 template <
typename T>
struct iterator_traits<fmt::basic_appender<T>> {
159 using iterator_category = output_iterator_tag;
160 using value_type = T;
161 using difference_type =
162 decltype(static_cast<int*>(
nullptr) - static_cast<int*>(
nullptr));
163 using pointer = void;
164 using reference = void;
170 #elif FMT_USE_EXCEPTIONS 171 # define FMT_THROW(x) throw x 173 # define FMT_THROW(x) ::fmt::assert_fail(__FILE__, __LINE__, (x).what()) 176 #ifdef __clang_analyzer__ 177 # define FMT_CLANG_ANALYZER 1 179 # define FMT_CLANG_ANALYZER 0 186 #if !defined(FMT_REDUCE_INT_INSTANTIATIONS) 187 # define FMT_REDUCE_INT_INSTANTIATIONS 0 192 template <
typename Char,
typename Traits,
typename Allocator>
193 struct is_contiguous<
std::basic_string<Char, Traits, Allocator>>
201 # if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION 202 # define FMT_BUILTIN_CLZ(n) __builtin_clz(n) 204 # if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION 205 # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) 212 #if FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) 215 # pragma intrinsic(_BitScanReverse) 217 # pragma intrinsic(_BitScanReverse64) 221 inline auto clz(uint32_t x) ->
int {
222 FMT_ASSERT(x != 0,
"");
223 FMT_MSC_WARNING(suppress : 6102)
225 _BitScanReverse(&r, x);
226 return 31 ^
static_cast<int>(r);
228 # define FMT_BUILTIN_CLZ(n) detail::clz(n) 230 inline auto clzll(uint64_t x) ->
int {
231 FMT_ASSERT(x != 0,
"");
232 FMT_MSC_WARNING(suppress : 6102)
235 _BitScanReverse64(&r, x);
238 if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
239 return 63 ^
static_cast<int>(r + 32);
241 _BitScanReverse(&r, static_cast<uint32_t>(x));
243 return 63 ^
static_cast<int>(r);
245 # define FMT_BUILTIN_CLZLL(n) detail::clzll(n) 246 #endif // FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) 248 FMT_CONSTEXPR
inline void abort_fuzzing_if(
bool condition) {
249 ignore_unused(condition);
251 if (condition)
throw std::runtime_error(
"fuzzing limit reached");
255 #if defined(FMT_USE_STRING_VIEW) 256 template <
typename Char>
using std_string_view = std::basic_string_view<Char>;
258 template <
typename Char>
struct std_string_view {
263 template <
typename Char, Char... C>
struct string_literal {
264 static constexpr Char value[
sizeof...(C)] = {C...};
266 return {value,
sizeof...(C)};
269 #if FMT_CPLUSPLUS < 201703L 270 template <
typename Char, Char... C>
271 constexpr Char string_literal<Char, C...>::value[
sizeof...(C)];
275 template <
typename To,
typename From, FMT_ENABLE_IF(sizeof(To) == sizeof(From))>
276 FMT_CONSTEXPR20
auto bit_cast(
const From& from) -> To {
277 #ifdef __cpp_lib_bit_cast 278 if (is_constant_evaluated())
return std::bit_cast<To>(from);
282 std::memcpy(static_cast<void*>(&to), &from,
sizeof(to));
286 inline auto is_big_endian() ->
bool {
289 #elif defined(__BIG_ENDIAN__) 291 #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) 292 return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;
295 char data[
sizeof(int)];
297 return bit_cast<bytes>(1).data[0] == 0;
301 class uint128_fallback {
306 constexpr uint128_fallback(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {}
307 constexpr uint128_fallback(uint64_t value = 0) : lo_(value), hi_(0) {}
309 constexpr
auto high() const noexcept -> uint64_t {
return hi_; }
310 constexpr
auto low() const noexcept -> uint64_t {
return lo_; }
312 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
313 constexpr
explicit operator T()
const {
314 return static_cast<T
>(lo_);
317 friend constexpr
auto operator==(
const uint128_fallback& lhs,
318 const uint128_fallback& rhs) ->
bool {
319 return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_;
321 friend constexpr
auto operator!=(
const uint128_fallback& lhs,
322 const uint128_fallback& rhs) ->
bool {
323 return !(lhs == rhs);
325 friend constexpr
auto operator>(
const uint128_fallback& lhs,
326 const uint128_fallback& rhs) ->
bool {
327 return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_;
329 friend constexpr
auto operator|(
const uint128_fallback& lhs,
330 const uint128_fallback& rhs)
331 -> uint128_fallback {
332 return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_};
334 friend constexpr
auto operator&(
const uint128_fallback& lhs,
335 const uint128_fallback& rhs)
336 -> uint128_fallback {
337 return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_};
339 friend constexpr
auto operator~(
const uint128_fallback& n)
340 -> uint128_fallback {
341 return {~n.hi_, ~n.lo_};
343 friend FMT_CONSTEXPR
auto operator+(
const uint128_fallback& lhs,
344 const uint128_fallback& rhs)
345 -> uint128_fallback {
346 auto result = uint128_fallback(lhs);
350 friend FMT_CONSTEXPR
auto operator*(
const uint128_fallback& lhs, uint32_t rhs)
351 -> uint128_fallback {
352 FMT_ASSERT(lhs.hi_ == 0,
"");
353 uint64_t hi = (lhs.lo_ >> 32) * rhs;
354 uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs;
355 uint64_t new_lo = (hi << 32) + lo;
356 return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo};
358 friend constexpr
auto operator-(
const uint128_fallback& lhs, uint64_t rhs)
359 -> uint128_fallback {
360 return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs};
362 FMT_CONSTEXPR
auto operator>>(
int shift)
const -> uint128_fallback {
363 if (shift == 64)
return {0, hi_};
364 if (shift > 64)
return uint128_fallback(0, hi_) >> (shift - 64);
365 return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)};
367 FMT_CONSTEXPR
auto operator<<(
int shift)
const -> uint128_fallback {
368 if (shift == 64)
return {lo_, 0};
369 if (shift > 64)
return uint128_fallback(lo_, 0) << (shift - 64);
370 return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)};
372 FMT_CONSTEXPR
auto operator>>=(
int shift) -> uint128_fallback& {
373 return *
this = *
this >> shift;
375 FMT_CONSTEXPR
void operator+=(uint128_fallback n) {
376 uint64_t new_lo = lo_ + n.lo_;
377 uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0);
378 FMT_ASSERT(new_hi >= hi_,
"");
382 FMT_CONSTEXPR
void operator&=(uint128_fallback n) {
387 FMT_CONSTEXPR20
auto operator+=(uint64_t n) noexcept -> uint128_fallback& {
388 if (is_constant_evaluated()) {
390 hi_ += (lo_ < n ? 1 : 0);
393 #if FMT_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__) 394 unsigned long long carry;
395 lo_ = __builtin_addcll(lo_, n, 0, &carry);
397 #elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__) 398 unsigned long long result;
399 auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result);
402 #elif defined(_MSC_VER) && defined(_M_X64) 403 auto carry = _addcarry_u64(0, lo_, n, &lo_);
404 _addcarry_u64(carry, hi_, 0, &hi_);
407 hi_ += (lo_ < n ? 1 : 0);
413 using uint128_t = conditional_t<FMT_USE_INT128, uint128_opt, uint128_fallback>;
416 using uintptr_t = ::uintptr_t;
418 using uintptr_t = uint128_t;
423 template <
typename T> constexpr
auto max_value() -> T {
424 return (std::numeric_limits<T>::max)();
426 template <
typename T> constexpr
auto num_bits() ->
int {
427 return std::numeric_limits<T>::digits;
430 template <> constexpr
auto num_bits<int128_opt>() ->
int {
return 128; }
431 template <> constexpr
auto num_bits<uint128_opt>() ->
int {
return 128; }
432 template <> constexpr
auto num_bits<uint128_fallback>() ->
int {
return 128; }
436 template <
typename To,
typename From, FMT_ENABLE_IF(sizeof(To) >
sizeof(From))>
437 inline auto bit_cast(
const From& from) -> To {
438 constexpr
auto size =
static_cast<int>(
sizeof(From) /
sizeof(
unsigned short));
440 unsigned short value[
static_cast<unsigned>(size)];
441 } data = bit_cast<data_t>(from);
443 if (const_check(is_big_endian())) {
444 for (
int i = 0; i < size; ++i)
445 result = (result << num_bits<unsigned short>()) | data.value[i];
447 for (
int i = size - 1; i >= 0; --i)
448 result = (result << num_bits<unsigned short>()) | data.value[i];
453 template <
typename UInt>
454 FMT_CONSTEXPR20
inline auto countl_zero_fallback(UInt n) ->
int {
456 constexpr UInt msb_mask =
static_cast<UInt
>(1) << (num_bits<UInt>() - 1);
457 for (; (n & msb_mask) == 0; n <<= 1) lz++;
461 FMT_CONSTEXPR20
inline auto countl_zero(uint32_t n) ->
int {
462 #ifdef FMT_BUILTIN_CLZ 463 if (!is_constant_evaluated())
return FMT_BUILTIN_CLZ(n);
465 return countl_zero_fallback(n);
468 FMT_CONSTEXPR20
inline auto countl_zero(uint64_t n) ->
int {
469 #ifdef FMT_BUILTIN_CLZLL 470 if (!is_constant_evaluated())
return FMT_BUILTIN_CLZLL(n);
472 return countl_zero_fallback(n);
475 FMT_INLINE
void assume(
bool condition) {
477 #if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION 478 __builtin_assume(condition);
479 #elif FMT_GCC_VERSION 480 if (!condition) __builtin_unreachable();
486 template <
typename OutputIt,
487 FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value&&
488 is_contiguous<typename OutputIt::container>::value)>
489 #if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION 490 __attribute__((no_sanitize(
"undefined")))
492 FMT_CONSTEXPR20
inline auto 493 reserve(OutputIt it,
size_t n) ->
typename OutputIt::value_type* {
494 auto& c = get_container(it);
495 size_t size = c.size();
500 template <
typename T>
501 FMT_CONSTEXPR20
inline auto reserve(basic_appender<T> it,
size_t n)
502 -> basic_appender<T> {
503 buffer<T>& buf = get_container(it);
504 buf.try_reserve(buf.size() + n);
508 template <
typename Iterator>
509 constexpr
auto reserve(Iterator& it,
size_t) -> Iterator& {
513 template <
typename OutputIt>
514 using reserve_iterator =
515 remove_reference_t<decltype(reserve(std::declval<OutputIt&>(), 0))>;
517 template <
typename T,
typename OutputIt>
518 constexpr
auto to_pointer(OutputIt,
size_t) -> T* {
521 template <
typename T> FMT_CONSTEXPR
auto to_pointer(T*& ptr,
size_t n) -> T* {
526 template <
typename T>
527 FMT_CONSTEXPR20
auto to_pointer(basic_appender<T> it,
size_t n) -> T* {
528 buffer<T>& buf = get_container(it);
529 buf.try_reserve(buf.size() + n);
530 auto size = buf.size();
531 if (buf.capacity() < size + n)
return nullptr;
532 buf.try_resize(size + n);
533 return buf.data() + size;
536 template <
typename OutputIt,
537 FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value&&
538 is_contiguous<typename OutputIt::container>::value)>
539 inline auto base_iterator(OutputIt it,
540 typename OutputIt::container_type::value_type*)
545 template <
typename Iterator>
546 constexpr
auto base_iterator(Iterator, Iterator it) -> Iterator {
552 template <
typename OutputIt,
typename Size,
typename T>
553 FMT_CONSTEXPR
auto fill_n(OutputIt out, Size count,
const T& value)
555 for (Size i = 0; i < count; ++i) *out++ = value;
558 template <
typename T,
typename Size>
559 FMT_CONSTEXPR20
auto fill_n(T* out, Size count,
char value) -> T* {
560 if (is_constant_evaluated())
return fill_n<T*, Size, T>(out, count, value);
561 static_assert(
sizeof(T) == 1,
562 "sizeof(T) must be 1 to use char for initialization");
563 std::memset(out, value, to_unsigned(count));
567 template <
typename OutChar,
typename InputIt,
typename OutputIt>
568 FMT_CONSTEXPR FMT_NOINLINE
auto copy_noinline(InputIt begin, InputIt end,
569 OutputIt out) -> OutputIt {
570 return copy<OutChar>(begin, end, out);
590 FMT_CONSTEXPR
inline auto utf8_decode(
const char* s, uint32_t* c,
int* e)
592 constexpr
int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
593 constexpr uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
594 constexpr
int shiftc[] = {0, 18, 12, 6, 0};
595 constexpr
int shifte[] = {0, 6, 4, 2, 0};
597 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" 598 [
static_cast<unsigned char>(*s) >> 3];
602 const char*
next = s + len + !len;
604 using uchar =
unsigned char;
608 *c = uint32_t(uchar(s[0]) & masks[len]) << 18;
609 *c |= uint32_t(uchar(s[1]) & 0x3f) << 12;
610 *c |= uint32_t(uchar(s[2]) & 0x3f) << 6;
611 *c |= uint32_t(uchar(s[3]) & 0x3f) << 0;
615 *e = (*c < mins[len]) << 6;
616 *e |= ((*c >> 11) == 0x1b) << 7;
617 *e |= (*c > 0x10FFFF) << 8;
618 *e |= (uchar(s[1]) & 0xc0) >> 2;
619 *e |= (uchar(s[2]) & 0xc0) >> 4;
620 *e |= uchar(s[3]) >> 6;
627 constexpr FMT_INLINE_VARIABLE uint32_t invalid_code_point = ~uint32_t();
631 template <
typename F>
632 FMT_CONSTEXPR
void for_each_codepoint(
string_view s, F f) {
633 auto decode = [f](
const char* buf_ptr,
const char* ptr) {
634 auto cp = uint32_t();
636 auto end = utf8_decode(buf_ptr, &cp, &
error);
637 bool result = f(
error ? invalid_code_point : cp,
639 return result ? (
error ? buf_ptr + 1 : end) :
nullptr;
643 const size_t block_size = 4;
644 if (s.
size() >= block_size) {
645 for (
auto end = p + s.
size() - block_size + 1; p < end;) {
650 auto num_chars_left = to_unsigned(s.
data() + s.
size() - p);
651 if (num_chars_left == 0)
return;
654 if (FMT_GCC_VERSION) num_chars_left &= 3;
655 char buf[2 * block_size - 1] = {};
656 copy<char>(p, p + num_chars_left, buf);
657 const char* buf_ptr = buf;
659 auto end = decode(buf_ptr, p);
663 }
while (buf_ptr < buf + num_chars_left);
666 FMT_CONSTEXPR
inline auto display_width_of(uint32_t cp) noexcept ->
size_t {
673 (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) ||
674 (cp >= 0xac00 && cp <= 0xd7a3) ||
675 (cp >= 0xf900 && cp <= 0xfaff) ||
676 (cp >= 0xfe10 && cp <= 0xfe19) ||
677 (cp >= 0xfe30 && cp <= 0xfe6f) ||
678 (cp >= 0xff00 && cp <= 0xff60) ||
679 (cp >= 0xffe0 && cp <= 0xffe6) ||
680 (cp >= 0x20000 && cp <= 0x2fffd) ||
681 (cp >= 0x30000 && cp <= 0x3fffd) ||
683 (cp >= 0x1f300 && cp <= 0x1f64f) ||
685 (cp >= 0x1f900 && cp <= 0x1f9ff))));
688 template <
typename T>
struct is_integral : std::is_integral<T> {};
689 template <>
struct is_integral<int128_opt> : std::true_type {};
690 template <>
struct is_integral<uint128_t> : std::true_type {};
692 template <
typename T>
694 std::integral_constant<bool, std::numeric_limits<T>::is_signed ||
695 std::is_same<T, int128_opt>::value>;
697 template <
typename T>
699 bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value &&
700 !std::is_same<T, char>::value &&
701 !std::is_same<T, wchar_t>::value>;
703 #if defined(FMT_USE_FLOAT128) 705 #elif FMT_CLANG_VERSION >= 309 && FMT_HAS_INCLUDE(<quadmath.h>) 706 # define FMT_USE_FLOAT128 1 707 #elif FMT_GCC_VERSION && defined(_GLIBCXX_USE_FLOAT128) && \ 708 !defined(__STRICT_ANSI__) 709 # define FMT_USE_FLOAT128 1 711 # define FMT_USE_FLOAT128 0 714 using float128 = __float128;
719 template <
typename T>
using is_float128 = std::is_same<T, float128>;
721 template <
typename T>
struct is_floating_point : std::is_floating_point<T> {};
722 template <>
struct is_floating_point<float128> : std::true_type {};
724 template <typename T, bool = is_floating_point<T>::value>
725 struct is_fast_float : bool_constant<std::numeric_limits<T>::is_iec559 &&
726 sizeof(T) <= sizeof(double)> {};
727 template <typename T> struct is_fast_float<T, false> : std::false_type {};
729 template <typename T>
730 using fast_float_t = conditional_t<sizeof(T) == sizeof(double), double, float>;
732 template <typename T>
733 using is_double_double = bool_constant<std::numeric_limits<T>::digits == 106>;
735 #ifndef FMT_USE_FULL_CACHE_DRAGONBOX
736 # define FMT_USE_FULL_CACHE_DRAGONBOX 0
742 template <typename T> struct allocator : private std::decay<void> {
743 using value_type = T;
745 auto allocate(size_t n) -> T* {
746 FMT_ASSERT(n <= max_value<size_t>() /
sizeof(T),
"");
747 T* p =
static_cast<T*
>(std::malloc(n *
sizeof(T)));
748 if (!p) FMT_THROW(std::bad_alloc());
752 void deallocate(T* p,
size_t) { std::free(p); }
754 constexpr
friend auto operator==(allocator, allocator) noexcept ->
bool {
757 constexpr
friend auto operator!=(allocator, allocator) noexcept ->
bool {
768 enum { inline_buffer_size = 500 };
783 template <
typename T,
size_t SIZE = inline_buffer_size,
784 typename Allocator = detail::allocator<T>>
790 FMT_NO_UNIQUE_ADDRESS Allocator alloc_;
793 FMT_CONSTEXPR20
void deallocate() {
794 T* data = this->data();
795 if (data != store_) alloc_.deallocate(data, this->capacity());
799 detail::abort_fuzzing_if(size > 5000);
801 const size_t max_size =
802 std::allocator_traits<Allocator>::max_size(
self.alloc_);
803 size_t old_capacity = buf.
capacity();
804 size_t new_capacity = old_capacity + old_capacity / 2;
805 if (size > new_capacity)
807 else if (new_capacity > max_size)
808 new_capacity = max_of(size, max_size);
809 T* old_data = buf.
data();
810 T* new_data =
self.alloc_.allocate(new_capacity);
812 detail::assume(buf.
size() <= new_capacity);
814 memcpy(new_data, old_data, buf.
size() *
sizeof(T));
815 self.set(new_data, new_capacity);
819 if (old_data !=
self.store_)
self.alloc_.deallocate(old_data, old_capacity);
823 using value_type = T;
824 using const_reference =
const T&;
827 const Allocator& alloc = Allocator())
829 this->
set(store_, SIZE);
830 if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T());
832 FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); }
835 template <
typename Alloc = Allocator,
836 FMT_ENABLE_IF(std::allocator_traits<Alloc>::
837 propagate_on_container_move_assignment::value)>
838 FMT_CONSTEXPR20
auto move_alloc(basic_memory_buffer& other) ->
bool {
839 alloc_ = std::move(other.alloc_);
843 template <
typename Alloc = Allocator,
844 FMT_ENABLE_IF(!std::allocator_traits<Alloc>::
845 propagate_on_container_move_assignment::value)>
846 FMT_CONSTEXPR20
auto move_alloc(basic_memory_buffer& other) ->
bool {
847 T* data = other.
data();
848 if (alloc_ == other.alloc_ || data == other.store_)
return true;
849 size_t size = other.
size();
852 detail::copy<T>(data, data + size, this->data());
857 FMT_CONSTEXPR20
void move(basic_memory_buffer& other) {
858 T* data = other.
data();
859 size_t size = other.
size(), capacity = other.
capacity();
860 if (!move_alloc(other))
return;
861 if (data == other.store_) {
862 this->
set(store_, capacity);
863 detail::copy<T>(other.store_, other.store_ + size, store_);
865 this->
set(data, capacity);
868 other.
set(other.store_, 0);
883 auto operator=(basic_memory_buffer&& other) noexcept -> basic_memory_buffer& {
884 FMT_ASSERT(
this != &other,
"");
891 auto get_allocator()
const -> Allocator {
return alloc_; }
895 FMT_CONSTEXPR
void resize(
size_t count) { this->try_resize(count); }
898 void reserve(
size_t new_capacity) { this->try_reserve(new_capacity); }
901 template <
typename ContiguousRange>
902 FMT_CONSTEXPR20
void append(
const ContiguousRange& range) {
903 append(range.data(), range.data() + range.size());
909 template <
size_t SIZE>
912 auto size = buf.
size();
913 detail::assume(size < std::string().max_size());
914 return {buf.
data(), size};
927 inline writer(FILE* f) : buf_(
nullptr), file_(f) {}
932 template <
typename... T>
void print(format_string<T...> fmt, T&&... args) {
934 fmt::format_to(appender(*buf_), fmt, std::forward<T>(args)...);
936 fmt::print(file_, fmt, std::forward<T>(args)...);
940 class string_buffer {
943 detail::container_buffer<std::string> buf_;
946 inline string_buffer() : buf_(str_) {}
948 inline operator writer() {
return buf_; }
949 inline auto str() -> std::string& {
return str_; }
952 template <
typename T,
size_t SIZE,
typename Allocator>
953 struct is_contiguous<basic_memory_buffer<T, SIZE, Allocator>> : std::true_type {
957 FMT_PRAGMA_CLANG(diagnostic ignored
"-Wweak-vtables")
959 class FMT_SO_VISIBILITY("default") format_error :
public std::runtime_error {
962 using std::runtime_error::runtime_error;
969 FMT_API
auto write_console(
int fd,
string_view text) -> bool;
974 template <
typename Char,
size_t N>
struct fixed_string {
975 FMT_CONSTEXPR20 fixed_string(
const Char (&s)[N]) {
976 detail::copy<Char, const Char*, Char*>(
static_cast<const Char*
>(s), s + N,
983 FMT_EXPORT
template <
typename Char,
size_t N>
984 constexpr
auto compile_string_to_view(
const Char (&s)[N])
988 return {s, N - (std::char_traits<Char>::to_int_type(s[N - 1]) == 0 ? 1 : 0)};
990 FMT_EXPORT
template <
typename Char>
998 template <typename T, FMT_ENABLE_IF(is_signed<T>::value)>
999 constexpr
auto is_negative(T value) ->
bool {
1002 template <typename T, FMT_ENABLE_IF(!is_signed<T>::value)>
1003 constexpr
auto is_negative(T) ->
bool {
1009 template <
typename T>
1010 using uint32_or_64_or_128_t =
1011 conditional_t<num_bits<T>() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS,
1013 conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>;
1014 template <
typename T>
1015 using uint64_or_128_t = conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>;
1017 #define FMT_POWERS_OF_10(factor) \ 1018 factor * 10, (factor) * 100, (factor) * 1000, (factor) * 10000, \ 1019 (factor) * 100000, (factor) * 1000000, (factor) * 10000000, \ 1020 (factor) * 100000000, (factor) * 1000000000 1024 inline auto digits2(
size_t value) ->
const char* {
1027 alignas(2)
static const char data[] =
1028 "0001020304050607080910111213141516171819" 1029 "2021222324252627282930313233343536373839" 1030 "4041424344454647484950515253545556575859" 1031 "6061626364656667686970717273747576777879" 1032 "8081828384858687888990919293949596979899";
1033 return &data[value * 2];
1036 template <
typename Char> constexpr
auto getsign(sign s) -> Char {
1037 return static_cast<char>(((
' ' << 24) | (
'+' << 16) | (
'-' << 8)) >>
1038 (
static_cast<int>(s) * 8));
1041 template <
typename T> FMT_CONSTEXPR
auto count_digits_fallback(T n) ->
int {
1047 if (n < 10)
return count;
1048 if (n < 100)
return count + 1;
1049 if (n < 1000)
return count + 2;
1050 if (n < 10000)
return count + 3;
1056 FMT_CONSTEXPR
inline auto count_digits(uint128_opt n) ->
int {
1057 return count_digits_fallback(n);
1061 #ifdef FMT_BUILTIN_CLZLL 1064 inline auto do_count_digits(uint64_t n) ->
int {
1069 static constexpr uint8_t bsr2log10[] = {
1070 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
1071 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
1072 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
1073 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20};
1074 auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63];
1075 static constexpr uint64_t zero_or_powers_of_10[] = {
1076 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL),
1077 10000000000000000000ULL};
1078 return t - (n < zero_or_powers_of_10[t]);
1084 FMT_CONSTEXPR20
inline auto count_digits(uint64_t n) ->
int {
1085 #ifdef FMT_BUILTIN_CLZLL 1086 if (!is_constant_evaluated() && !FMT_OPTIMIZE_SIZE)
return do_count_digits(n);
1088 return count_digits_fallback(n);
1092 template <
int BITS,
typename UInt>
1093 FMT_CONSTEXPR
auto count_digits(UInt n) ->
int {
1094 #ifdef FMT_BUILTIN_CLZ 1095 if (!is_constant_evaluated() && num_bits<UInt>() == 32)
1096 return (FMT_BUILTIN_CLZ(static_cast<uint32_t>(n) | 1) ^ 31) / BITS + 1;
1103 }
while ((m >>= BITS) != 0);
1108 #ifdef FMT_BUILTIN_CLZ 1111 FMT_INLINE
auto do_count_digits(uint32_t n) ->
int {
1114 # define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T) 1115 static constexpr uint64_t table[] = {
1116 FMT_INC(0), FMT_INC(0), FMT_INC(0),
1117 FMT_INC(10), FMT_INC(10), FMT_INC(10),
1118 FMT_INC(100), FMT_INC(100), FMT_INC(100),
1119 FMT_INC(1000), FMT_INC(1000), FMT_INC(1000),
1120 FMT_INC(10000), FMT_INC(10000), FMT_INC(10000),
1121 FMT_INC(100000), FMT_INC(100000), FMT_INC(100000),
1122 FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000),
1123 FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000),
1124 FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000),
1125 FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000),
1126 FMT_INC(1000000000), FMT_INC(1000000000)
1128 auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31];
1129 return static_cast<int>((n + inc) >> 32);
1134 FMT_CONSTEXPR20
inline auto count_digits(uint32_t n) ->
int {
1135 #ifdef FMT_BUILTIN_CLZ 1136 if (!is_constant_evaluated() && !FMT_OPTIMIZE_SIZE)
return do_count_digits(n);
1138 return count_digits_fallback(n);
1141 template <
typename Int> constexpr
auto digits10() noexcept ->
int {
1142 return std::numeric_limits<Int>::digits10;
1144 template <> constexpr
auto digits10<int128_opt>() noexcept ->
int {
return 38; }
1145 template <> constexpr
auto digits10<uint128_t>() noexcept ->
int {
return 38; }
1147 template <
typename Char>
struct thousands_sep_result {
1148 std::string grouping;
1152 template <
typename Char>
1153 FMT_API
auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result<Char>;
1154 template <
typename Char>
1155 inline auto thousands_sep(locale_ref loc) -> thousands_sep_result<Char> {
1156 auto result = thousands_sep_impl<char>(loc);
1157 return {result.grouping, Char(result.thousands_sep)};
1160 inline auto thousands_sep(locale_ref loc) -> thousands_sep_result<wchar_t> {
1161 return thousands_sep_impl<wchar_t>(loc);
1164 template <
typename Char>
1165 FMT_API
auto decimal_point_impl(locale_ref loc) -> Char;
1166 template <
typename Char>
inline auto decimal_point(locale_ref loc) -> Char {
1167 return Char(decimal_point_impl<char>(loc));
1169 template <>
inline auto decimal_point(locale_ref loc) ->
wchar_t {
1170 return decimal_point_impl<wchar_t>(loc);
1173 #ifndef FMT_HEADER_ONLY 1175 extern template FMT_API
auto thousands_sep_impl<char>(locale_ref)
1176 -> thousands_sep_result<char>;
1177 extern template FMT_API
auto thousands_sep_impl<wchar_t>(locale_ref)
1178 -> thousands_sep_result<wchar_t>;
1179 extern template FMT_API
auto decimal_point_impl(locale_ref) -> char;
1180 extern template FMT_API
auto decimal_point_impl(locale_ref) -> wchar_t;
1182 #endif // FMT_HEADER_ONLY 1185 template <
typename Char>
auto equal2(
const Char* lhs,
const char* rhs) ->
bool {
1186 return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]);
1188 inline auto equal2(
const char* lhs,
const char* rhs) ->
bool {
1189 return memcmp(lhs, rhs, 2) == 0;
1193 template <
typename Char>
1194 FMT_CONSTEXPR20 FMT_INLINE
void write2digits(Char* out,
size_t value) {
1195 if (!is_constant_evaluated() && std::is_same<Char, char>::value &&
1196 !FMT_OPTIMIZE_SIZE) {
1197 memcpy(out, digits2(value), 2);
1200 *out++ =
static_cast<Char
>(
'0' + value / 10);
1201 *out =
static_cast<Char
>(
'0' + value % 10);
1206 template <
typename Char,
typename UInt>
1207 FMT_CONSTEXPR20
auto do_format_decimal(Char* out, UInt value,
int size)
1209 FMT_ASSERT(size >= count_digits(value),
"invalid digit count");
1210 unsigned n = to_unsigned(size);
1211 while (value >= 100) {
1216 write2digits(out + n, static_cast<unsigned>(value % 100));
1221 write2digits(out + n, static_cast<unsigned>(value));
1223 out[--n] =
static_cast<Char
>(
'0' + value);
1228 template <
typename Char,
typename UInt>
1229 FMT_CONSTEXPR FMT_INLINE
auto format_decimal(Char* out, UInt value,
1230 int num_digits) -> Char* {
1231 do_format_decimal(out, value, num_digits);
1232 return out + num_digits;
1235 template <
typename Char,
typename UInt,
typename OutputIt,
1236 FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)>
1237 FMT_CONSTEXPR
auto format_decimal(OutputIt out, UInt value,
int num_digits)
1239 if (
auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
1240 do_format_decimal(ptr, value, num_digits);
1244 char buffer[digits10<UInt>() + 1];
1245 if (is_constant_evaluated()) fill_n(buffer,
sizeof(buffer),
'\0');
1246 do_format_decimal(buffer, value, num_digits);
1247 return copy_noinline<Char>(buffer, buffer + num_digits, out);
1250 template <
typename Char,
typename UInt>
1251 FMT_CONSTEXPR
auto do_format_base2e(
int base_bits, Char* out, UInt value,
1252 int size,
bool upper =
false) -> Char* {
1255 const char* digits = upper ?
"0123456789ABCDEF" :
"0123456789abcdef";
1256 unsigned digit =
static_cast<unsigned>(value & ((1u << base_bits) - 1));
1257 *--out =
static_cast<Char
>(base_bits < 4 ? static_cast<char>(
'0' + digit)
1259 }
while ((value >>= base_bits) != 0);
1264 template <
typename Char,
typename UInt>
1265 FMT_CONSTEXPR
auto format_base2e(
int base_bits, Char* out, UInt value,
1266 int num_digits,
bool upper =
false) -> Char* {
1267 do_format_base2e(base_bits, out, value, num_digits, upper);
1268 return out + num_digits;
1271 template <
typename Char,
typename OutputIt,
typename UInt,
1272 FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value)>
1273 FMT_CONSTEXPR
inline auto format_base2e(
int base_bits, OutputIt out, UInt value,
1274 int num_digits,
bool upper =
false)
1276 if (
auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
1277 format_base2e(base_bits, ptr, value, num_digits, upper);
1281 char buffer[num_bits<UInt>()];
1282 if (is_constant_evaluated()) fill_n(buffer,
sizeof(buffer),
'\0');
1283 format_base2e(base_bits, buffer, value, num_digits, upper);
1284 return detail::copy_noinline<Char>(buffer, buffer + num_digits, out);
1288 class utf8_to_utf16 {
1295 return {&buffer_[0], size()};
1297 inline auto size()
const ->
size_t {
return buffer_.
size() - 1; }
1298 inline auto c_str()
const ->
const wchar_t* {
return &buffer_[0]; }
1299 inline auto str()
const -> std::wstring {
return {&buffer_[0], size()}; }
1302 enum class to_utf8_error_policy { abort, replace };
1305 template <
typename WChar,
typename Buffer = memory_buffer>
class to_utf8 {
1312 to_utf8_error_policy policy = to_utf8_error_policy::abort) {
1313 static_assert(
sizeof(WChar) == 2 ||
sizeof(WChar) == 4,
1314 "expected utf16 or utf32");
1315 if (!convert(s, policy)) {
1316 FMT_THROW(std::runtime_error(
sizeof(WChar) == 2 ?
"invalid utf16" 1317 :
"invalid utf32"));
1321 auto size()
const ->
size_t {
return buffer_.size() - 1; }
1322 auto c_str()
const ->
const char* {
return &buffer_[0]; }
1323 auto str()
const -> std::string {
return std::string(&buffer_[0], size()); }
1329 to_utf8_error_policy policy = to_utf8_error_policy::abort)
1331 if (!convert(buffer_, s, policy))
return false;
1332 buffer_.push_back(0);
1336 to_utf8_error_policy policy = to_utf8_error_policy::abort)
1338 for (
auto p = s.begin(); p != s.end(); ++p) {
1339 uint32_t c =
static_cast<uint32_t
>(*p);
1340 if (
sizeof(WChar) == 2 && c >= 0xd800 && c <= 0xdfff) {
1343 if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) {
1344 if (policy == to_utf8_error_policy::abort)
return false;
1349 c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;
1352 buf.push_back(static_cast<char>(c));
1353 }
else if (c < 0x800) {
1354 buf.push_back(static_cast<char>(0xc0 | (c >> 6)));
1355 buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
1356 }
else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
1357 buf.push_back(static_cast<char>(0xe0 | (c >> 12)));
1358 buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
1359 buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
1360 }
else if (c >= 0x10000 && c <= 0x10ffff) {
1361 buf.push_back(static_cast<char>(0xf0 | (c >> 18)));
1362 buf.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
1363 buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
1364 buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
1374 FMT_INLINE
auto umul128(uint64_t x, uint64_t y) noexcept -> uint128_fallback {
1376 auto p =
static_cast<uint128_opt
>(x) * static_cast<uint128_opt>(y);
1377 return {
static_cast<uint64_t
>(p >> 64), static_cast<uint64_t>(p)};
1378 #elif defined(_MSC_VER) && defined(_M_X64) 1379 auto hi = uint64_t();
1380 auto lo = _umul128(x, y, &hi);
1383 const uint64_t mask =
static_cast<uint64_t
>(max_value<uint32_t>());
1385 uint64_t a = x >> 32;
1386 uint64_t b = x & mask;
1387 uint64_t c = y >> 32;
1388 uint64_t d = y & mask;
1390 uint64_t ac = a * c;
1391 uint64_t bc = b * c;
1392 uint64_t ad = a * d;
1393 uint64_t bd = b * d;
1395 uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask);
1397 return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32),
1398 (intermediate << 32) + (bd & mask)};
1402 namespace dragonbox {
1405 inline auto floor_log10_pow2(
int e) noexcept ->
int {
1406 FMT_ASSERT(e <= 2620 && e >= -2620,
"too large exponent");
1407 static_assert((-1 >> 1) == -1,
"right shift is not arithmetic");
1408 return (e * 315653) >> 20;
1411 inline auto floor_log2_pow10(
int e) noexcept ->
int {
1412 FMT_ASSERT(e <= 1233 && e >= -1233,
"too large exponent");
1413 return (e * 1741647) >> 19;
1417 inline auto umul128_upper64(uint64_t x, uint64_t y) noexcept -> uint64_t {
1419 auto p =
static_cast<uint128_opt
>(x) * static_cast<uint128_opt>(y);
1420 return static_cast<uint64_t
>(p >> 64);
1421 #elif defined(_MSC_VER) && defined(_M_X64) 1422 return __umulh(x, y);
1424 return umul128(x, y).high();
1430 inline auto umul192_upper128(uint64_t x, uint128_fallback y) noexcept
1431 -> uint128_fallback {
1432 uint128_fallback r = umul128(x, y.high());
1433 r += umul128_upper64(x, y.low());
1437 FMT_API
auto get_cached_power(
int k) noexcept -> uint128_fallback;
1440 template <
typename T,
typename Enable =
void>
struct float_info;
1442 template <>
struct float_info<float> {
1443 using carrier_uint = uint32_t;
1444 static const int exponent_bits = 8;
1445 static const int kappa = 1;
1446 static const int big_divisor = 100;
1447 static const int small_divisor = 10;
1448 static const int min_k = -31;
1449 static const int max_k = 46;
1450 static const int shorter_interval_tie_lower_threshold = -35;
1451 static const int shorter_interval_tie_upper_threshold = -35;
1454 template <>
struct float_info<double> {
1455 using carrier_uint = uint64_t;
1456 static const int exponent_bits = 11;
1457 static const int kappa = 2;
1458 static const int big_divisor = 1000;
1459 static const int small_divisor = 100;
1460 static const int min_k = -292;
1461 static const int max_k = 341;
1462 static const int shorter_interval_tie_lower_threshold = -77;
1463 static const int shorter_interval_tie_upper_threshold = -77;
1467 template <
typename T>
1468 struct float_info<T, enable_if_t<std::numeric_limits<T>::digits == 64 ||
1469 std::numeric_limits<T>::digits == 113 ||
1470 is_float128<T>::value>> {
1471 using carrier_uint = detail::uint128_t;
1472 static const int exponent_bits = 15;
1476 template <
typename T>
1477 struct float_info<T, enable_if_t<is_double_double<T>::value>> {
1478 using carrier_uint = detail::uint128_t;
1481 template <
typename T>
struct decimal_fp {
1482 using significand_type =
typename float_info<T>::carrier_uint;
1483 significand_type significand;
1487 template <
typename T> FMT_API
auto to_decimal(T x) noexcept -> decimal_fp<T>;
1491 template <
typename Float> constexpr
auto has_implicit_bit() ->
bool {
1493 return std::numeric_limits<Float>::digits != 64;
1498 template <
typename Float> constexpr
auto num_significand_bits() ->
int {
1500 return is_float128<Float>() ? 112
1501 : (std::numeric_limits<Float>::digits -
1502 (has_implicit_bit<Float>() ? 1 : 0));
1505 template <
typename Float>
1506 constexpr
auto exponent_mask() ->
1507 typename dragonbox::float_info<Float>::carrier_uint {
1508 using float_uint =
typename dragonbox::float_info<Float>::carrier_uint;
1509 return ((float_uint(1) << dragonbox::float_info<Float>::exponent_bits) - 1)
1510 << num_significand_bits<Float>();
1512 template <
typename Float> constexpr
auto exponent_bias() ->
int {
1514 return is_float128<Float>() ? 16383
1515 : std::numeric_limits<Float>::max_exponent - 1;
1518 FMT_CONSTEXPR
inline auto compute_exp_size(
int exp) ->
int {
1519 auto prefix_size = 2;
1520 auto abs_exp = exp >= 0 ? exp : -exp;
1521 if (abs_exp < 100)
return prefix_size + 2;
1522 return prefix_size + (abs_exp >= 1000 ? 4 : 3);
1526 template <
typename Char,
typename OutputIt>
1527 FMT_CONSTEXPR
auto write_exponent(
int exp, OutputIt out) -> OutputIt {
1528 FMT_ASSERT(-10000 < exp && exp < 10000,
"exponent out of range");
1530 *out++ =
static_cast<Char
>(
'-');
1533 *out++ =
static_cast<Char
>(
'+');
1535 auto uexp =
static_cast<uint32_t
>(exp);
1536 if (is_constant_evaluated()) {
1537 if (uexp < 10) *out++ =
'0';
1538 return format_decimal<Char>(out, uexp, count_digits(uexp));
1541 const char* top = digits2(uexp / 100);
1542 if (uexp >= 1000u) *out++ =
static_cast<Char
>(top[0]);
1543 *out++ =
static_cast<Char
>(top[1]);
1546 const char* d = digits2(uexp);
1547 *out++ =
static_cast<Char
>(d[0]);
1548 *out++ =
static_cast<Char
>(d[1]);
1553 template <
typename F>
struct basic_fp {
1557 static constexpr
int num_significand_bits =
1558 static_cast<int>(
sizeof(F) * num_bits<unsigned char>());
1560 constexpr basic_fp() : f(0), e(0) {}
1561 constexpr basic_fp(uint64_t f_val,
int e_val) : f(f_val), e(e_val) {}
1564 template <
typename Float> FMT_CONSTEXPR basic_fp(Float n) { assign(n); }
1567 template <typename Float, FMT_ENABLE_IF(!is_double_double<Float>::value)>
1568 FMT_CONSTEXPR
auto assign(Float n) ->
bool {
1569 static_assert(std::numeric_limits<Float>::digits <= 113,
"unsupported FP");
1571 using carrier_uint =
typename dragonbox::float_info<Float>::carrier_uint;
1572 const auto num_float_significand_bits =
1573 detail::num_significand_bits<Float>();
1574 const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
1575 const auto significand_mask = implicit_bit - 1;
1576 auto u = bit_cast<carrier_uint>(n);
1577 f =
static_cast<F
>(u & significand_mask);
1578 auto biased_e =
static_cast<int>((u & exponent_mask<Float>()) >>
1579 num_float_significand_bits);
1582 auto is_predecessor_closer = f == 0 && biased_e > 1;
1585 else if (has_implicit_bit<Float>())
1586 f += static_cast<F>(implicit_bit);
1587 e = biased_e - exponent_bias<Float>() - num_float_significand_bits;
1588 if (!has_implicit_bit<Float>()) ++e;
1589 return is_predecessor_closer;
1592 template <typename Float, FMT_ENABLE_IF(is_double_double<Float>::value)>
1593 FMT_CONSTEXPR
auto assign(Float n) ->
bool {
1594 static_assert(std::numeric_limits<double>::is_iec559,
"unsupported FP");
1595 return assign(static_cast<double>(n));
1599 using fp = basic_fp<unsigned long long>;
1602 template <
int SHIFT = 0,
typename F>
1603 FMT_CONSTEXPR
auto normalize(basic_fp<F> value) -> basic_fp<F> {
1605 const auto implicit_bit = F(1) << num_significand_bits<double>();
1606 const auto shifted_implicit_bit = implicit_bit << SHIFT;
1607 while ((value.f & shifted_implicit_bit) == 0) {
1612 const auto offset = basic_fp<F>::num_significand_bits -
1613 num_significand_bits<double>() - SHIFT - 1;
1620 FMT_CONSTEXPR
inline auto multiply(uint64_t lhs, uint64_t rhs) -> uint64_t {
1622 auto product =
static_cast<__uint128_t
>(lhs) * rhs;
1623 auto f =
static_cast<uint64_t
>(product >> 64);
1624 return (static_cast<uint64_t>(product) & (1ULL << 63)) != 0 ? f + 1 : f;
1627 uint64_t mask = (1ULL << 32) - 1;
1628 uint64_t a = lhs >> 32, b = lhs & mask;
1629 uint64_t c = rhs >> 32, d = rhs & mask;
1630 uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
1632 uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
1633 return ac + (ad >> 32) + (bc >> 32) + (mid >> 32);
1637 FMT_CONSTEXPR
inline auto operator*(fp x, fp y) -> fp {
1638 return {multiply(x.f, y.f), x.e + y.e + 64};
1641 template <
typename T,
bool doublish = num_bits<T>() == num_bits<
double>()>
1642 using convert_float_result =
1643 conditional_t<std::is_same<T, float>::value || doublish, double, T>;
1645 template <
typename T>
1646 constexpr
auto convert_float(T value) -> convert_float_result<T> {
1647 return static_cast<convert_float_result<T>
>(value);
1650 template <
bool C,
typename T,
typename F, FMT_ENABLE_IF(C)>
1651 auto select(T true_value, F) -> T {
1654 template <
bool C,
typename T,
typename F, FMT_ENABLE_IF(!C)>
1655 auto select(T, F false_value) -> F {
1659 template <
typename Char,
typename OutputIt>
1660 FMT_CONSTEXPR FMT_NOINLINE
auto fill(OutputIt it,
size_t n,
1661 const basic_specs& specs) -> OutputIt {
1662 auto fill_size = specs.fill_size();
1663 if (fill_size == 1)
return detail::fill_n(it, n, specs.fill_unit<Char>());
1664 if (
const Char* data = specs.fill<Char>()) {
1665 for (
size_t i = 0; i < n; ++i) it = copy<Char>(data, data + fill_size, it);
1673 template <
typename Char, align default_align = align::left,
typename OutputIt,
1675 FMT_CONSTEXPR
auto write_padded(OutputIt out,
const format_specs& specs,
1676 size_t size,
size_t width, F&& f) -> OutputIt {
1677 static_assert(default_align == align::left || default_align == align::right,
1679 unsigned spec_width = to_unsigned(specs.width);
1680 size_t padding = spec_width > width ? spec_width - width : 0;
1684 default_align == align::left ?
"\x1f\x1f\x00\x01" :
"\x00\x1f\x00\x01";
1685 size_t left_padding = padding >> shifts[
static_cast<int>(specs.align())];
1686 size_t right_padding = padding - left_padding;
1687 auto it = reserve(out, size + padding * specs.fill_size());
1688 if (left_padding != 0) it = fill<Char>(it, left_padding, specs);
1690 if (right_padding != 0) it = fill<Char>(it, right_padding, specs);
1691 return base_iterator(out, it);
1694 template <
typename Char, align default_align = align::left,
typename OutputIt,
1696 constexpr
auto write_padded(OutputIt out,
const format_specs& specs,
1697 size_t size, F&& f) -> OutputIt {
1698 return write_padded<Char, default_align>(out, specs, size, size, f);
1701 template <
typename Char, align default_align = align::left,
typename OutputIt>
1702 FMT_CONSTEXPR
auto write_bytes(OutputIt out,
string_view bytes,
1703 const format_specs& specs = {}) -> OutputIt {
1704 return write_padded<Char, default_align>(
1705 out, specs, bytes.
size(), [bytes](reserve_iterator<OutputIt> it) {
1706 const char* data = bytes.
data();
1707 return copy<Char>(data, data + bytes.
size(), it);
1711 template <
typename Char,
typename OutputIt,
typename UIntPtr>
1712 auto write_ptr(OutputIt out, UIntPtr value,
const format_specs* specs)
1714 int num_digits = count_digits<4>(value);
1715 auto size = to_unsigned(num_digits) + size_t(2);
1716 auto write = [=](reserve_iterator<OutputIt> it) {
1717 *it++ =
static_cast<Char
>(
'0');
1718 *it++ =
static_cast<Char
>(
'x');
1719 return format_base2e<Char>(4, it, value, num_digits);
1721 return specs ? write_padded<Char, align::right>(out, *specs, size, write)
1722 : base_iterator(out, write(reserve(out, size)));
1726 FMT_API
auto is_printable(uint32_t cp) -> bool;
1728 inline auto needs_escape(uint32_t cp) ->
bool {
1729 if (cp < 0x20 || cp == 0x7f || cp ==
'"' || cp ==
'\\')
return true;
1730 if (const_check(FMT_OPTIMIZE_SIZE > 1))
return false;
1731 return !is_printable(cp);
1734 template <
typename Char>
struct find_escape_result {
1740 template <
typename Char>
1741 auto find_escape(
const Char* begin,
const Char* end)
1742 -> find_escape_result<Char> {
1743 for (; begin != end; ++begin) {
1744 uint32_t cp =
static_cast<unsigned_char<Char>
>(*begin);
1745 if (const_check(
sizeof(Char) == 1) && cp >= 0x80)
continue;
1746 if (needs_escape(cp))
return {begin, begin + 1, cp};
1748 return {begin,
nullptr, 0};
1751 inline auto find_escape(
const char* begin,
const char* end)
1752 -> find_escape_result<char> {
1753 if (const_check(!use_utf8))
return find_escape<char>(begin, end);
1754 auto result = find_escape_result<char>{end,
nullptr, 0};
1755 for_each_codepoint(
string_view(begin, to_unsigned(end - begin)),
1757 if (needs_escape(cp)) {
1758 result = {sv.begin(), sv.end(), cp};
1766 template <
size_t w
idth,
typename Char,
typename OutputIt>
1767 auto write_codepoint(OutputIt out,
char prefix, uint32_t cp) -> OutputIt {
1768 *out++ =
static_cast<Char
>(
'\\');
1769 *out++ =
static_cast<Char
>(prefix);
1771 fill_n(buf, width, static_cast<Char>(
'0'));
1772 format_base2e(4, buf, cp, width);
1773 return copy<Char>(buf, buf + width, out);
1776 template <
typename OutputIt,
typename Char>
1777 auto write_escaped_cp(OutputIt out,
const find_escape_result<Char>& escape)
1779 auto c =
static_cast<Char
>(escape.cp);
1780 switch (escape.cp) {
1782 *out++ =
static_cast<Char
>(
'\\');
1783 c =
static_cast<Char
>(
'n');
1786 *out++ =
static_cast<Char
>(
'\\');
1787 c =
static_cast<Char
>(
'r');
1790 *out++ =
static_cast<Char
>(
'\\');
1791 c =
static_cast<Char
>(
't');
1793 case '"': FMT_FALLTHROUGH;
1794 case '\'': FMT_FALLTHROUGH;
1795 case '\\': *out++ =
static_cast<Char
>(
'\\');
break;
1797 if (escape.cp < 0x100)
return write_codepoint<2, Char>(out,
'x', escape.cp);
1798 if (escape.cp < 0x10000)
1799 return write_codepoint<4, Char>(out,
'u', escape.cp);
1800 if (escape.cp < 0x110000)
1801 return write_codepoint<8, Char>(out,
'U', escape.cp);
1803 escape.begin, to_unsigned(escape.end - escape.begin))) {
1804 out = write_codepoint<2, Char>(out,
'x',
1805 static_cast<uint32_t
>(escape_char) & 0xFF);
1813 template <
typename Char,
typename OutputIt>
1816 *out++ =
static_cast<Char
>(
'"');
1817 auto begin = str.begin(), end = str.end();
1819 auto escape = find_escape(begin, end);
1820 out = copy<Char>(begin, escape.begin, out);
1823 out = write_escaped_cp<OutputIt, Char>(out, escape);
1824 }
while (begin != end);
1825 *out++ =
static_cast<Char
>(
'"');
1829 template <
typename Char,
typename OutputIt>
1830 auto write_escaped_char(OutputIt out, Char v) -> OutputIt {
1831 Char v_array[1] = {v};
1832 *out++ =
static_cast<Char
>(
'\'');
1833 if ((needs_escape(static_cast<uint32_t>(v)) && v != static_cast<Char>(
'"')) ||
1834 v ==
static_cast<Char
>(
'\'')) {
1835 out = write_escaped_cp(out,
1836 find_escape_result<Char>{v_array, v_array + 1,
1837 static_cast<uint32_t
>(v)});
1841 *out++ =
static_cast<Char
>(
'\'');
1845 template <
typename Char,
typename OutputIt>
1846 FMT_CONSTEXPR
auto write_char(OutputIt out, Char value,
1847 const format_specs& specs) -> OutputIt {
1848 bool is_debug = specs.type() == presentation_type::debug;
1849 return write_padded<Char>(out, specs, 1, [=](reserve_iterator<OutputIt> it) {
1850 if (is_debug)
return write_escaped_char(it, value);
1856 template <
typename Char>
class digit_grouping {
1858 std::string grouping_;
1859 std::basic_string<Char> thousands_sep_;
1862 std::string::const_iterator group;
1865 auto initial_state()
const -> next_state {
return {grouping_.begin(), 0}; }
1868 auto next(next_state& state)
const ->
int {
1869 if (thousands_sep_.empty())
return max_value<int>();
1870 if (state.group == grouping_.end())
return state.pos += grouping_.back();
1871 if (*state.group <= 0 || *state.group == max_value<char>())
1872 return max_value<int>();
1873 state.pos += *state.group++;
1878 explicit digit_grouping(locale_ref loc,
bool localized =
true) {
1879 if (!localized)
return;
1880 auto sep = thousands_sep<Char>(loc);
1881 grouping_ = sep.grouping;
1882 if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep);
1884 digit_grouping(std::string grouping, std::basic_string<Char> sep)
1885 : grouping_(std::move(grouping)), thousands_sep_(std::move(sep)) {}
1887 auto has_separator()
const ->
bool {
return !thousands_sep_.empty(); }
1889 auto count_separators(
int num_digits)
const ->
int {
1891 auto state = initial_state();
1892 while (num_digits >
next(state)) ++count;
1897 template <
typename Out,
typename C>
1899 auto num_digits =
static_cast<int>(digits.
size());
1901 separators.push_back(0);
1902 auto state = initial_state();
1903 while (
int i =
next(state)) {
1904 if (i >= num_digits)
break;
1905 separators.push_back(i);
1907 for (
int i = 0, sep_index = static_cast<int>(separators.size() - 1);
1908 i < num_digits; ++i) {
1909 if (num_digits - i == separators[sep_index]) {
1910 out = copy<Char>(thousands_sep_.data(),
1911 thousands_sep_.data() + thousands_sep_.size(), out);
1914 *out++ =
static_cast<Char
>(digits[to_unsigned(i)]);
1920 FMT_CONSTEXPR
inline void prefix_append(
unsigned& prefix,
unsigned value) {
1921 prefix |= prefix != 0 ? value << 8 : value;
1922 prefix += (1u + (value > 0xff ? 1 : 0)) << 24;
1926 template <
typename OutputIt,
typename UInt,
typename Char>
1927 auto write_int(OutputIt out, UInt value,
unsigned prefix,
1928 const format_specs& specs,
const digit_grouping<Char>& grouping)
1930 static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value,
"");
1933 switch (specs.type()) {
1934 default: FMT_ASSERT(
false,
""); FMT_FALLTHROUGH;
1935 case presentation_type::none:
1936 case presentation_type::dec:
1937 num_digits = count_digits(value);
1938 format_decimal<char>(appender(buffer), value, num_digits);
1940 case presentation_type::hex:
1942 prefix_append(prefix,
unsigned(specs.upper() ?
'X' :
'x') << 8 |
'0');
1943 num_digits = count_digits<4>(value);
1944 format_base2e<char>(4, appender(buffer), value, num_digits, specs.upper());
1946 case presentation_type::oct:
1947 num_digits = count_digits<3>(value);
1950 if (specs.alt() && specs.precision <= num_digits && value != 0)
1951 prefix_append(prefix,
'0');
1952 format_base2e<char>(3, appender(buffer), value, num_digits);
1954 case presentation_type::bin:
1956 prefix_append(prefix,
unsigned(specs.upper() ?
'B' :
'b') << 8 |
'0');
1957 num_digits = count_digits<1>(value);
1958 format_base2e<char>(1, appender(buffer), value, num_digits);
1960 case presentation_type::chr:
1961 return write_char<Char>(out,
static_cast<Char
>(value), specs);
1964 unsigned size = (prefix != 0 ? prefix >> 24 : 0) + to_unsigned(num_digits) +
1965 to_unsigned(grouping.count_separators(num_digits));
1966 return write_padded<Char, align::right>(
1967 out, specs, size, size, [&](reserve_iterator<OutputIt> it) {
1968 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
1969 *it++ = static_cast<Char>(p & 0xff);
1970 return grouping.apply(it,
string_view(buffer.data(), buffer.size()));
1976 FMT_API
auto write_loc(appender out, loc_value value,
const format_specs& specs,
1977 locale_ref loc) -> bool;
1978 auto write_loc(basic_appender<wchar_t> out, loc_value value,
1979 const format_specs& specs, locale_ref loc) -> bool;
1981 template <
typename OutputIt>
1982 inline auto write_loc(OutputIt,
const loc_value&,
const format_specs&,
1983 locale_ref) ->
bool {
1987 template <
typename UInt>
struct write_int_arg {
1992 template <
typename T>
1993 FMT_CONSTEXPR
auto make_write_int_arg(T value, sign s)
1994 -> write_int_arg<uint32_or_64_or_128_t<T>> {
1996 auto abs_value =
static_cast<uint32_or_64_or_128_t<T>
>(value);
1997 if (is_negative(value)) {
1998 prefix = 0x01000000 |
'-';
1999 abs_value = 0 - abs_value;
2001 constexpr
unsigned prefixes[4] = {0, 0, 0x1000000u |
'+', 0x1000000u |
' '};
2002 prefix = prefixes[
static_cast<int>(s)];
2004 return {abs_value, prefix};
2007 template <
typename Char =
char>
struct loc_writer {
2008 basic_appender<Char> out;
2009 const format_specs& specs;
2010 std::basic_string<Char> sep;
2011 std::string grouping;
2012 std::basic_string<Char> decimal_point;
2014 template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
2015 auto operator()(T value) ->
bool {
2016 auto arg = make_write_int_arg(value, specs.sign());
2017 write_int(out,
static_cast<uint64_or_128_t<T>
>(arg.abs_value), arg.prefix,
2018 specs, digit_grouping<Char>(grouping, sep));
2022 template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
2023 auto operator()(T) ->
bool {
2029 struct size_padding {
2033 FMT_CONSTEXPR size_padding(
int num_digits,
unsigned prefix,
2034 const format_specs& specs)
2035 : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) {
2036 if (specs.align() == align::numeric) {
2037 auto width = to_unsigned(specs.width);
2039 padding = width - size;
2042 }
else if (specs.precision > num_digits) {
2043 size = (prefix >> 24) + to_unsigned(specs.precision);
2044 padding = to_unsigned(specs.precision - num_digits);
2049 template <
typename Char,
typename OutputIt,
typename T>
2050 FMT_CONSTEXPR FMT_INLINE
auto write_int(OutputIt out, write_int_arg<T> arg,
2051 const format_specs& specs) -> OutputIt {
2052 static_assert(std::is_same<T, uint32_or_64_or_128_t<T>>::value,
"");
2054 constexpr
size_t buffer_size = num_bits<T>();
2055 char buffer[buffer_size];
2056 if (is_constant_evaluated()) fill_n(buffer, buffer_size,
'\0');
2057 const char* begin =
nullptr;
2058 const char* end = buffer + buffer_size;
2060 auto abs_value = arg.abs_value;
2061 auto prefix = arg.prefix;
2062 switch (specs.type()) {
2063 default: FMT_ASSERT(
false,
""); FMT_FALLTHROUGH;
2064 case presentation_type::none:
2065 case presentation_type::dec:
2066 begin = do_format_decimal(buffer, abs_value, buffer_size);
2068 case presentation_type::hex:
2069 begin = do_format_base2e(4, buffer, abs_value, buffer_size, specs.upper());
2071 prefix_append(prefix,
unsigned(specs.upper() ?
'X' :
'x') << 8 |
'0');
2073 case presentation_type::oct: {
2074 begin = do_format_base2e(3, buffer, abs_value, buffer_size);
2077 auto num_digits = end - begin;
2078 if (specs.alt() && specs.precision <= num_digits && abs_value != 0)
2079 prefix_append(prefix,
'0');
2082 case presentation_type::bin:
2083 begin = do_format_base2e(1, buffer, abs_value, buffer_size);
2085 prefix_append(prefix,
unsigned(specs.upper() ?
'B' :
'b') << 8 |
'0');
2087 case presentation_type::chr:
2088 return write_char<Char>(out,
static_cast<Char
>(abs_value), specs);
2094 int num_digits =
static_cast<int>(end - begin);
2096 if ((specs.width | (specs.precision + 1)) == 0) {
2097 auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24));
2098 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
2099 *it++ = static_cast<Char>(p & 0xff);
2100 return base_iterator(out, copy<Char>(begin, end, it));
2102 auto sp = size_padding(num_digits, prefix, specs);
2103 unsigned padding = sp.padding;
2104 return write_padded<Char, align::right>(
2105 out, specs, sp.size, [=](reserve_iterator<OutputIt> it) {
2106 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
2107 *it++ = static_cast<Char>(p & 0xff);
2108 it = detail::fill_n(it, padding, static_cast<Char>(
'0'));
2109 return copy<Char>(begin, end, it);
2113 template <
typename Char,
typename OutputIt,
typename T>
2114 FMT_CONSTEXPR FMT_NOINLINE
auto write_int_noinline(OutputIt out,
2115 write_int_arg<T> arg,
2116 const format_specs& specs)
2118 return write_int<Char>(out, arg, specs);
2121 template <
typename Char,
typename T,
2122 FMT_ENABLE_IF(is_integral<T>::value &&
2123 !std::is_same<T, bool>::value &&
2124 !std::is_same<T, Char>::value)>
2125 FMT_CONSTEXPR FMT_INLINE
auto write(basic_appender<Char> out, T value,
2126 const format_specs& specs, locale_ref loc)
2127 -> basic_appender<Char> {
2128 if (specs.localized() && write_loc(out, value, specs, loc))
return out;
2129 return write_int_noinline<Char>(out, make_write_int_arg(value, specs.sign()),
2134 template <
typename Char,
typename OutputIt,
typename T,
2135 FMT_ENABLE_IF(is_integral<T>::value &&
2136 !std::is_same<T, bool>::value &&
2137 !std::is_same<T, Char>::value &&
2138 !std::is_same<OutputIt, basic_appender<Char>>::value)>
2139 FMT_CONSTEXPR FMT_INLINE
auto write(OutputIt out, T value,
2140 const format_specs& specs, locale_ref loc)
2142 if (specs.localized() && write_loc(out, value, specs, loc))
return out;
2143 return write_int<Char>(out, make_write_int_arg(value, specs.sign()), specs);
2146 template <
typename Char,
typename OutputIt>
2147 FMT_CONSTEXPR
auto write(OutputIt out, Char value,
const format_specs& specs,
2148 locale_ref loc = {}) -> OutputIt {
2150 using unsigned_type =
2151 conditional_t<std::is_same<Char, char>::value,
unsigned char,
unsigned>;
2152 return check_char_specs(specs)
2153 ? write_char<Char>(out, value, specs)
2154 : write<Char>(out, static_cast<unsigned_type>(value), specs, loc);
2157 template <
typename Char,
typename OutputIt,
2158 FMT_ENABLE_IF(std::is_same<Char, char>::value)>
2160 const format_specs& specs) -> OutputIt {
2161 bool is_debug = specs.type() == presentation_type::debug;
2162 if (specs.precision < 0 && specs.width == 0) {
2163 auto&& it = reserve(out, s.
size());
2164 return is_debug ? write_escaped_string(it, s) : copy<char>(s, it);
2167 size_t display_width_limit =
2168 specs.precision < 0 ? SIZE_MAX : to_unsigned(specs.precision);
2169 size_t display_width =
2170 !is_debug || specs.precision == 0 ? 0 : 1;
2171 size_t size = !is_debug || specs.precision == 0 ? 0 : 1;
2172 for_each_codepoint(s, [&](uint32_t cp,
string_view sv) {
2173 if (is_debug && needs_escape(cp)) {
2174 counting_buffer<char> buf;
2175 write_escaped_cp(basic_appender<char>(buf),
2176 find_escape_result<char>{sv.begin(), sv.end(), cp});
2179 size_t cp_width = buf.count();
2180 if (display_width + cp_width <= display_width_limit) {
2181 display_width += cp_width;
2184 if (display_width < display_width_limit && sv.end() == s.end()) {
2191 size += display_width_limit - display_width;
2192 display_width = display_width_limit;
2196 size_t cp_width = display_width_of(cp);
2197 if (cp_width + display_width <= display_width_limit) {
2198 display_width += cp_width;
2201 if (is_debug && display_width < display_width_limit &&
2202 sv.end() == s.end()) {
2212 struct bounded_output_iterator {
2213 reserve_iterator<OutputIt> underlying_iterator;
2216 FMT_CONSTEXPR
auto operator*() -> bounded_output_iterator& {
return *
this; }
2217 FMT_CONSTEXPR
auto operator++() -> bounded_output_iterator& {
2220 FMT_CONSTEXPR
auto operator++(
int) -> bounded_output_iterator& {
2223 FMT_CONSTEXPR
auto operator=(
char c) -> bounded_output_iterator& {
2225 *underlying_iterator++ = c;
2232 return write_padded<char>(
2233 out, specs, size, display_width, [=](reserve_iterator<OutputIt> it) {
2235 ? write_escaped_string(bounded_output_iterator{it, size}, s)
2236 .underlying_iterator
2237 : copy<char>(s.
data(), s.
data() + size, it);
2241 template <
typename Char,
typename OutputIt,
2242 FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
2244 const format_specs& specs) -> OutputIt {
2245 auto data = s.
data();
2246 auto size = s.
size();
2247 if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
2248 size = to_unsigned(specs.precision);
2250 bool is_debug = specs.type() == presentation_type::debug;
2252 auto buf = counting_buffer<Char>();
2253 write_escaped_string(basic_appender<Char>(buf), s);
2257 return write_padded<Char>(
2258 out, specs, size, [=](reserve_iterator<OutputIt> it) {
2259 return is_debug ? write_escaped_string(it, s)
2260 : copy<Char>(data, data + size, it);
2264 template <
typename Char,
typename OutputIt>
2266 const format_specs& specs, locale_ref) -> OutputIt {
2267 return write<Char>(out, s, specs);
2270 template <
typename Char,
typename OutputIt>
2271 FMT_CONSTEXPR
auto write(OutputIt out,
const Char* s,
const format_specs& specs,
2272 locale_ref) -> OutputIt {
2273 if (specs.type() == presentation_type::pointer)
2274 return write_ptr<Char>(out, bit_cast<uintptr_t>(s), &specs);
2275 if (!s) report_error(
"string pointer is null");
2279 template <
typename Char,
typename OutputIt,
typename T,
2280 FMT_ENABLE_IF(is_integral<T>::value &&
2281 !std::is_same<T, bool>::value &&
2282 !std::is_same<T, Char>::value)>
2283 FMT_CONSTEXPR
auto write(OutputIt out, T value) -> OutputIt {
2284 auto abs_value =
static_cast<uint32_or_64_or_128_t<T>
>(value);
2285 bool negative = is_negative(value);
2287 if (negative) abs_value = ~abs_value + 1;
2288 int num_digits = count_digits(abs_value);
2289 auto size = (negative ? 1 : 0) + static_cast<size_t>(num_digits);
2290 if (
auto ptr = to_pointer<Char>(out, size)) {
2291 if (negative) *ptr++ =
static_cast<Char
>(
'-');
2292 format_decimal<Char>(ptr, abs_value, num_digits);
2295 if (negative) *out++ =
static_cast<Char
>(
'-');
2296 return format_decimal<Char>(out, abs_value, num_digits);
2299 template <
typename Char>
2300 FMT_CONSTEXPR
auto parse_align(
const Char* begin,
const Char* end,
2301 format_specs& specs) ->
const Char* {
2302 FMT_ASSERT(begin != end,
"");
2303 auto alignment = align::none;
2304 auto p = begin + code_point_length(begin);
2305 if (end - p <= 0) p = begin;
2307 switch (to_ascii(*p)) {
2308 case '<': alignment = align::left;
break;
2309 case '>': alignment = align::right;
break;
2310 case '^': alignment = align::center;
break;
2312 if (alignment != align::none) {
2315 if (c ==
'}')
return begin;
2317 report_error(
"invalid fill character '{'");
2326 }
else if (p == begin) {
2331 specs.set_align(alignment);
2335 template <
typename Char,
typename OutputIt>
2336 FMT_CONSTEXPR20
auto write_nonfinite(OutputIt out,
bool isnan,
2337 format_specs specs, sign s) -> OutputIt {
2339 isnan ? (specs.upper() ?
"NAN" :
"nan") : (specs.upper() ?
"INF" :
"inf");
2340 constexpr
size_t str_size = 3;
2341 auto size = str_size + (s != sign::none ? 1 : 0);
2343 const bool is_zero_fill =
2344 specs.fill_size() == 1 && specs.fill_unit<Char>() ==
'0';
2345 if (is_zero_fill) specs.set_fill(
' ');
2346 return write_padded<Char>(out, specs, size,
2347 [=](reserve_iterator<OutputIt> it) {
2348 if (s != sign::none)
2349 *it++ = detail::getsign<Char>(s);
2350 return copy<Char>(str, str + str_size, it);
2355 struct big_decimal_fp {
2356 const char* significand;
2357 int significand_size;
2361 constexpr
auto get_significand_size(
const big_decimal_fp& f) ->
int {
2362 return f.significand_size;
2364 template <
typename T>
2365 inline auto get_significand_size(
const dragonbox::decimal_fp<T>& f) ->
int {
2366 return count_digits(f.significand);
2369 template <
typename Char,
typename OutputIt>
2370 constexpr
auto write_significand(OutputIt out,
const char* significand,
2371 int significand_size) -> OutputIt {
2372 return copy<Char>(significand, significand + significand_size, out);
2374 template <
typename Char,
typename OutputIt,
typename UInt>
2375 inline auto write_significand(OutputIt out, UInt significand,
2376 int significand_size) -> OutputIt {
2377 return format_decimal<Char>(out, significand, significand_size);
2379 template <
typename Char,
typename OutputIt,
typename T,
typename Grouping>
2380 FMT_CONSTEXPR20
auto write_significand(OutputIt out, T significand,
2381 int significand_size,
int exponent,
2382 const Grouping& grouping) -> OutputIt {
2383 if (!grouping.has_separator()) {
2384 out = write_significand<Char>(out, significand, significand_size);
2385 return detail::fill_n(out, exponent, static_cast<Char>(
'0'));
2388 write_significand<char>(appender(buffer), significand, significand_size);
2389 detail::fill_n(appender(buffer), exponent,
'0');
2390 return grouping.apply(out,
string_view(buffer.data(), buffer.size()));
2393 template <
typename Char,
typename UInt,
2394 FMT_ENABLE_IF(std::is_integral<UInt>::value)>
2395 inline auto write_significand(Char* out, UInt significand,
int significand_size,
2396 int integral_size, Char decimal_point) -> Char* {
2397 if (!decimal_point)
return format_decimal(out, significand, significand_size);
2398 out += significand_size + 1;
2400 int floating_size = significand_size - integral_size;
2401 for (
int i = floating_size / 2; i > 0; --i) {
2403 write2digits(out, static_cast<size_t>(significand % 100));
2406 if (floating_size % 2 != 0) {
2407 *--out =
static_cast<Char
>(
'0' + significand % 10);
2410 *--out = decimal_point;
2411 format_decimal(out - integral_size, significand, integral_size);
2415 template <
typename OutputIt,
typename UInt,
typename Char,
2416 FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)>
2417 inline auto write_significand(OutputIt out, UInt significand,
2418 int significand_size,
int integral_size,
2419 Char decimal_point) -> OutputIt {
2421 Char buffer[digits10<UInt>() + 2];
2422 auto end = write_significand(buffer, significand, significand_size,
2423 integral_size, decimal_point);
2424 return detail::copy_noinline<Char>(buffer, end, out);
2427 template <
typename OutputIt,
typename Char>
2428 FMT_CONSTEXPR
auto write_significand(OutputIt out,
const char* significand,
2429 int significand_size,
int integral_size,
2430 Char decimal_point) -> OutputIt {
2431 out = detail::copy_noinline<Char>(significand, significand + integral_size,
2433 if (!decimal_point)
return out;
2434 *out++ = decimal_point;
2435 return detail::copy_noinline<Char>(significand + integral_size,
2436 significand + significand_size, out);
2439 template <
typename OutputIt,
typename Char,
typename T,
typename Grouping>
2440 FMT_CONSTEXPR20
auto write_significand(OutputIt out, T significand,
2441 int significand_size,
int integral_size,
2443 const Grouping& grouping) -> OutputIt {
2444 if (!grouping.has_separator()) {
2445 return write_significand(out, significand, significand_size, integral_size,
2449 write_significand(basic_appender<Char>(buffer), significand, significand_size,
2450 integral_size, decimal_point);
2453 return detail::copy_noinline<Char>(buffer.data() + integral_size,
2459 template <
typename T> FMT_CONSTEVAL
auto exp_upper() ->
int {
2460 return std::numeric_limits<T>::digits10 != 0
2461 ? min_of(16, std::numeric_limits<T>::digits10 + 1)
2467 constexpr
auto use_fixed(
int exp,
int exp_upper) ->
bool {
2468 return exp >= -4 && exp < exp_upper;
2471 template <
typename Char>
class fallback_digit_grouping {
2473 constexpr fallback_digit_grouping(locale_ref,
bool) {}
2475 constexpr
auto has_separator()
const ->
bool {
return false; }
2477 constexpr
auto count_separators(
int)
const ->
int {
return 0; }
2479 template <
typename Out,
typename C>
2485 template <
typename Char,
typename Grouping,
typename OutputIt,
2487 FMT_CONSTEXPR20
auto write_fixed(OutputIt out,
const DecimalFP& f,
2488 int significand_size, Char decimal_point,
2489 const format_specs& specs, sign s,
2490 locale_ref loc = {}) -> OutputIt {
2491 using iterator = reserve_iterator<OutputIt>;
2493 int exp = f.exponent + significand_size;
2494 long long size = significand_size + (s != sign::none ? 1 : 0);
2495 if (f.exponent >= 0) {
2498 int num_zeros = specs.precision - exp;
2499 abort_fuzzing_if(num_zeros > 5000);
2502 if (num_zeros <= 0 && specs.type() != presentation_type::fixed)
2504 if (num_zeros > 0) size += num_zeros;
2506 auto grouping = Grouping(loc, specs.localized());
2507 size += grouping.count_separators(exp);
2508 return write_padded<Char, align::right>(
2509 out, specs, to_unsigned(size), [&](iterator it) {
2510 if (s != sign::none) *it++ = detail::getsign<Char>(s);
2511 it = write_significand<Char>(it, f.significand, significand_size,
2512 f.exponent, grouping);
2513 if (!specs.alt())
return it;
2514 *it++ = decimal_point;
2515 return num_zeros > 0 ? detail::fill_n(it, num_zeros, Char(
'0')) : it;
2520 int num_zeros = specs.alt() ? specs.precision - significand_size : 0;
2521 size += 1 + max_of(num_zeros, 0);
2522 auto grouping = Grouping(loc, specs.localized());
2523 size += grouping.count_separators(exp);
2524 return write_padded<Char, align::right>(
2525 out, specs, to_unsigned(size), [&](iterator it) {
2526 if (s != sign::none) *it++ = detail::getsign<Char>(s);
2527 it = write_significand(it, f.significand, significand_size, exp,
2528 decimal_point, grouping);
2529 return num_zeros > 0 ? detail::fill_n(it, num_zeros, Char(
'0')) : it;
2533 int num_zeros = -exp;
2534 if (significand_size == 0 && specs.precision >= 0 &&
2535 specs.precision < num_zeros) {
2536 num_zeros = specs.precision;
2538 bool pointy = num_zeros != 0 || significand_size != 0 || specs.alt();
2539 size += 1 + (pointy ? 1 : 0) + num_zeros;
2540 return write_padded<Char, align::right>(
2541 out, specs, to_unsigned(size), [&](iterator it) {
2542 if (s != sign::none) *it++ = detail::getsign<Char>(s);
2544 if (!pointy)
return it;
2545 *it++ = decimal_point;
2546 it = detail::fill_n(it, num_zeros, Char(
'0'));
2547 return write_significand<Char>(it, f.significand, significand_size);
2551 template <
typename Char,
typename Grouping,
typename OutputIt,
2553 FMT_CONSTEXPR20
auto do_write_float(OutputIt out,
const DecimalFP& f,
2554 const format_specs& specs, sign s,
2555 int exp_upper, locale_ref loc) -> OutputIt {
2556 Char point = specs.localized() ? detail::decimal_point<Char>(loc) : Char(
'.');
2557 int significand_size = get_significand_size(f);
2558 int exp = f.exponent + significand_size - 1;
2559 if (specs.type() == presentation_type::fixed ||
2560 (specs.type() != presentation_type::exp &&
2561 use_fixed(exp, specs.precision > 0 ? specs.precision : exp_upper))) {
2562 return write_fixed<Char, Grouping>(out, f, significand_size, point, specs,
2568 long long size = significand_size + (s != sign::none ? 1 : 0);
2570 num_zeros = max_of(specs.precision - significand_size, 0);
2572 }
else if (significand_size == 1) {
2575 size += (point ? 1 : 0) + compute_exp_size(exp);
2576 char exp_char = specs.upper() ?
'E' :
'e';
2577 auto write = [=](reserve_iterator<OutputIt> it) {
2578 if (s != sign::none) *it++ = detail::getsign<Char>(s);
2580 it = write_significand(it, f.significand, significand_size, 1, point);
2581 if (num_zeros > 0) it = detail::fill_n(it, num_zeros, Char(
'0'));
2582 *it++ = Char(exp_char);
2583 return write_exponent<Char>(exp, it);
2585 auto usize = to_unsigned(size);
2586 return specs.width > 0
2587 ? write_padded<Char, align::right>(out, specs, usize, write)
2588 : base_iterator(out, write(reserve(out, usize)));
2591 template <
typename Char,
typename OutputIt,
typename DecimalFP>
2592 FMT_CONSTEXPR20
auto write_float(OutputIt out,
const DecimalFP& f,
2593 const format_specs& specs, sign s,
2594 int exp_upper, locale_ref loc) -> OutputIt {
2595 if (is_constant_evaluated()) {
2596 return do_write_float<Char, fallback_digit_grouping<Char>>(out, f, specs, s,
2599 return do_write_float<Char, digit_grouping<Char>>(out, f, specs, s,
2604 template <
typename T> constexpr
auto isnan(T value) ->
bool {
2605 return value != value;
2608 template <
typename T,
typename Enable =
void>
2609 struct has_isfinite : std::false_type {};
2611 template <
typename T>
2612 struct has_isfinite<T, enable_if_t<sizeof(std::isfinite(T())) != 0>>
2613 : std::true_type {};
2615 template <
typename T,
2616 FMT_ENABLE_IF(is_floating_point<T>::value&& has_isfinite<T>::value)>
2617 FMT_CONSTEXPR20
auto isfinite(T value) ->
bool {
2618 constexpr T inf = T(std::numeric_limits<double>::infinity());
2619 if (is_constant_evaluated())
2620 return !detail::isnan(value) && value < inf && value > -inf;
2621 return std::isfinite(value);
2623 template <typename T, FMT_ENABLE_IF(!has_isfinite<T>::value)>
2624 FMT_CONSTEXPR
auto isfinite(T value) ->
bool {
2625 T inf = T(std::numeric_limits<double>::infinity());
2627 return !detail::isnan(value) && value < inf && value > -inf;
2630 template <typename T, FMT_ENABLE_IF(is_floating_point<T>::value)>
2631 FMT_INLINE FMT_CONSTEXPR
auto signbit(T value) ->
bool {
2632 if (is_constant_evaluated()) {
2633 #ifdef __cpp_if_constexpr 2634 if constexpr (std::numeric_limits<double>::is_iec559) {
2635 auto bits = detail::bit_cast<uint64_t>(
static_cast<double>(value));
2636 return (bits >> (num_bits<uint64_t>() - 1)) != 0;
2640 return std::signbit(static_cast<double>(value));
2643 inline FMT_CONSTEXPR20
void adjust_precision(
int& precision,
int exp10) {
2646 if (exp10 > 0 && precision > max_value<int>() - exp10)
2647 FMT_THROW(format_error(
"number is too big"));
2654 using bigit = uint32_t;
2655 using double_bigit = uint64_t;
2656 enum { bigit_bits = num_bits<bigit>() };
2657 enum { bigits_capacity = 32 };
2661 friend struct formatter<bigint>;
2663 FMT_CONSTEXPR
auto get_bigit(
int i)
const -> bigit {
2664 return i >= exp_ && i < num_bigits() ? bigits_[i - exp_] : 0;
2667 FMT_CONSTEXPR
void subtract_bigits(
int index, bigit other, bigit& borrow) {
2668 auto result = double_bigit(bigits_[index]) - other - borrow;
2669 bigits_[index] =
static_cast<bigit
>(result);
2670 borrow =
static_cast<bigit
>(result >> (bigit_bits * 2 - 1));
2673 FMT_CONSTEXPR
void remove_leading_zeros() {
2674 int num_bigits =
static_cast<int>(bigits_.
size()) - 1;
2675 while (num_bigits > 0 && bigits_[num_bigits] == 0) --num_bigits;
2676 bigits_.
resize(to_unsigned(num_bigits + 1));
2680 FMT_CONSTEXPR
void subtract_aligned(
const bigint& other) {
2681 FMT_ASSERT(other.exp_ >= exp_,
"unaligned bigints");
2682 FMT_ASSERT(compare(*
this, other) >= 0,
"");
2684 int i = other.exp_ - exp_;
2685 for (
size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j)
2686 subtract_bigits(i, other.bigits_[j], borrow);
2687 if (borrow != 0) subtract_bigits(i, 0, borrow);
2688 FMT_ASSERT(borrow == 0,
"");
2689 remove_leading_zeros();
2692 FMT_CONSTEXPR
void multiply(uint32_t value) {
2694 const double_bigit wide_value = value;
2695 for (
size_t i = 0, n = bigits_.
size(); i < n; ++i) {
2696 double_bigit result = bigits_[i] * wide_value + carry;
2697 bigits_[i] =
static_cast<bigit
>(result);
2698 carry =
static_cast<bigit
>(result >> bigit_bits);
2700 if (carry != 0) bigits_.push_back(carry);
2703 template <typename UInt, FMT_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
2704 std::is_same<UInt, uint128_t>::value)>
2705 FMT_CONSTEXPR
void multiply(UInt value) {
2707 conditional_t<std::is_same<UInt, uint128_t>::value, uint64_t, uint32_t>;
2708 const int shift = num_bits<half_uint>() - bigit_bits;
2709 const UInt lower =
static_cast<half_uint
>(value);
2710 const UInt upper = value >> num_bits<half_uint>();
2712 for (
size_t i = 0, n = bigits_.
size(); i < n; ++i) {
2713 UInt result = lower * bigits_[i] +
static_cast<bigit
>(carry);
2714 carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) +
2715 (carry >> bigit_bits);
2716 bigits_[i] =
static_cast<bigit
>(result);
2718 while (carry != 0) {
2719 bigits_.push_back(static_cast<bigit>(carry));
2720 carry >>= bigit_bits;
2724 template <typename UInt, FMT_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
2725 std::is_same<UInt, uint128_t>::value)>
2726 FMT_CONSTEXPR
void assign(UInt n) {
2727 size_t num_bigits = 0;
2729 bigits_[num_bigits++] =
static_cast<bigit
>(n);
2732 bigits_.
resize(num_bigits);
2737 FMT_CONSTEXPR bigint() : exp_(0) {}
2738 explicit bigint(uint64_t n) { assign(n); }
2740 bigint(
const bigint&) =
delete;
2741 void operator=(
const bigint&) =
delete;
2743 FMT_CONSTEXPR
void assign(
const bigint& other) {
2744 auto size = other.bigits_.size();
2746 auto data = other.bigits_.data();
2747 copy<bigit>(data, data + size, bigits_.
data());
2751 template <
typename Int> FMT_CONSTEXPR
void operator=(Int n) {
2752 FMT_ASSERT(n > 0,
"");
2753 assign(uint64_or_128_t<Int>(n));
2756 FMT_CONSTEXPR
auto num_bigits()
const ->
int {
2757 return static_cast<int>(bigits_.
size()) + exp_;
2760 FMT_CONSTEXPR
auto operator<<=(
int shift) -> bigint& {
2761 FMT_ASSERT(shift >= 0,
"");
2762 exp_ += shift / bigit_bits;
2763 shift %= bigit_bits;
2764 if (shift == 0)
return *
this;
2766 for (
size_t i = 0, n = bigits_.
size(); i < n; ++i) {
2767 bigit c = bigits_[i] >> (bigit_bits - shift);
2768 bigits_[i] = (bigits_[i] << shift) + carry;
2771 if (carry != 0) bigits_.push_back(carry);
2775 template <
typename Int> FMT_CONSTEXPR
auto operator*=(Int value) -> bigint& {
2776 FMT_ASSERT(value > 0,
"");
2777 multiply(uint32_or_64_or_128_t<Int>(value));
2781 friend FMT_CONSTEXPR
auto compare(
const bigint& b1,
const bigint& b2) ->
int {
2782 int num_bigits1 = b1.num_bigits(), num_bigits2 = b2.num_bigits();
2783 if (num_bigits1 != num_bigits2)
return num_bigits1 > num_bigits2 ? 1 : -1;
2784 int i =
static_cast<int>(b1.bigits_.size()) - 1;
2785 int j =
static_cast<int>(b2.bigits_.size()) - 1;
2787 if (end < 0) end = 0;
2788 for (; i >= end; --i, --j) {
2789 bigit b1_bigit = b1.bigits_[i], b2_bigit = b2.bigits_[j];
2790 if (b1_bigit != b2_bigit)
return b1_bigit > b2_bigit ? 1 : -1;
2792 if (i != j)
return i > j ? 1 : -1;
2797 friend FMT_CONSTEXPR
auto add_compare(
const bigint& lhs1,
const bigint& lhs2,
2798 const bigint& rhs) ->
int {
2799 int max_lhs_bigits = max_of(lhs1.num_bigits(), lhs2.num_bigits());
2800 int num_rhs_bigits = rhs.num_bigits();
2801 if (max_lhs_bigits + 1 < num_rhs_bigits)
return -1;
2802 if (max_lhs_bigits > num_rhs_bigits)
return 1;
2803 double_bigit borrow = 0;
2804 int min_exp = min_of(min_of(lhs1.exp_, lhs2.exp_), rhs.exp_);
2805 for (
int i = num_rhs_bigits - 1; i >= min_exp; --i) {
2806 double_bigit
sum = double_bigit(lhs1.get_bigit(i)) + lhs2.get_bigit(i);
2807 bigit rhs_bigit = rhs.get_bigit(i);
2808 if (sum > rhs_bigit + borrow)
return 1;
2809 borrow = rhs_bigit + borrow -
sum;
2810 if (borrow > 1)
return -1;
2811 borrow <<= bigit_bits;
2813 return borrow != 0 ? -1 : 0;
2817 FMT_CONSTEXPR20
void assign_pow10(
int exp) {
2818 FMT_ASSERT(exp >= 0,
"");
2819 if (exp == 0)
return *
this = 1;
2820 int bitmask = 1 << (num_bits<unsigned>() -
2821 countl_zero(static_cast<uint32_t>(exp)) - 1);
2826 while (bitmask != 0) {
2828 if ((exp & bitmask) != 0) *
this *= 5;
2834 FMT_CONSTEXPR20
void square() {
2835 int num_bigits =
static_cast<int>(bigits_.
size());
2836 int num_result_bigits = 2 * num_bigits;
2838 bigits_.
resize(to_unsigned(num_result_bigits));
2839 auto sum = uint128_t();
2840 for (
int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) {
2843 for (
int i = 0, j = bigit_index; j >= 0; ++i, --j) {
2845 sum += double_bigit(n[i]) * n[j];
2847 bigits_[bigit_index] =
static_cast<bigit
>(
sum);
2848 sum >>= num_bits<bigit>();
2851 for (
int bigit_index = num_bigits; bigit_index < num_result_bigits;
2853 for (
int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;)
2854 sum += double_bigit(n[i++]) * n[j--];
2855 bigits_[bigit_index] =
static_cast<bigit
>(
sum);
2856 sum >>= num_bits<bigit>();
2858 remove_leading_zeros();
2864 FMT_CONSTEXPR
void align(
const bigint& other) {
2865 int exp_difference = exp_ - other.exp_;
2866 if (exp_difference <= 0)
return;
2867 int num_bigits =
static_cast<int>(bigits_.
size());
2868 bigits_.
resize(to_unsigned(num_bigits + exp_difference));
2869 for (
int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j)
2870 bigits_[j] = bigits_[i];
2871 fill_n(bigits_.
data(), to_unsigned(exp_difference), 0U);
2872 exp_ -= exp_difference;
2877 FMT_CONSTEXPR
auto divmod_assign(
const bigint& divisor) ->
int {
2878 FMT_ASSERT(
this != &divisor,
"");
2879 if (compare(*
this, divisor) < 0)
return 0;
2880 FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0,
"");
2884 subtract_aligned(divisor);
2886 }
while (compare(*
this, divisor) >= 0);
2893 predecessor_closer = 1,
2901 FMT_CONSTEXPR20
inline void format_dragon(basic_fp<uint128_t> value,
2902 unsigned flags,
int num_digits,
2903 buffer<char>& buf,
int& exp10) {
2909 bigint* upper =
nullptr;
2913 bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0;
2914 int shift = is_predecessor_closer ? 2 : 1;
2916 numerator = value.f;
2917 numerator <<= value.e + shift;
2920 if (is_predecessor_closer) {
2922 upper_store <<= value.e + 1;
2923 upper = &upper_store;
2925 denominator.assign_pow10(exp10);
2926 denominator <<= shift;
2927 }
else if (exp10 < 0) {
2928 numerator.assign_pow10(-exp10);
2929 lower.assign(numerator);
2930 if (is_predecessor_closer) {
2931 upper_store.assign(numerator);
2933 upper = &upper_store;
2935 numerator *= value.f;
2936 numerator <<= shift;
2938 denominator <<= shift - value.e;
2940 numerator = value.f;
2941 numerator <<= shift;
2942 denominator.assign_pow10(exp10);
2943 denominator <<= shift - value.e;
2945 if (is_predecessor_closer) {
2946 upper_store = 1ULL << 1;
2947 upper = &upper_store;
2950 int even =
static_cast<int>((value.f & 1) == 0);
2951 if (!upper) upper = &lower;
2952 bool shortest = num_digits < 0;
2953 if ((flags & dragon::fixup) != 0) {
2954 if (add_compare(numerator, *upper, denominator) + even <= 0) {
2957 if (num_digits < 0) {
2959 if (upper != &lower) *upper *= 10;
2962 if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1);
2968 char* data = buf.data();
2970 int digit = numerator.divmod_assign(denominator);
2971 bool low = compare(numerator, lower) - even < 0;
2973 bool high = add_compare(numerator, *upper, denominator) + even > 0;
2974 data[num_digits++] =
static_cast<char>(
'0' + digit);
2977 ++data[num_digits - 1];
2979 int result = add_compare(numerator, numerator, denominator);
2981 if (result > 0 || (result == 0 && (digit % 2) != 0))
2982 ++data[num_digits - 1];
2984 buf.try_resize(to_unsigned(num_digits));
2985 exp10 -= num_digits - 1;
2990 if (upper != &lower) *upper *= 10;
2994 exp10 -= num_digits - 1;
2995 if (num_digits <= 0) {
2997 if (num_digits == 0) {
2999 digit = add_compare(numerator, numerator, denominator) > 0 ?
'1' :
'0';
3001 buf.push_back(digit);
3004 buf.try_resize(to_unsigned(num_digits));
3005 for (
int i = 0; i < num_digits - 1; ++i) {
3006 int digit = numerator.divmod_assign(denominator);
3007 buf[i] =
static_cast<char>(
'0' + digit);
3010 int digit = numerator.divmod_assign(denominator);
3011 auto result = add_compare(numerator, numerator, denominator);
3012 if (result > 0 || (result == 0 && (digit % 2) != 0)) {
3014 const auto overflow =
'0' + 10;
3015 buf[num_digits - 1] = overflow;
3017 for (
int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) {
3021 if (buf[0] == overflow) {
3023 if ((flags & dragon::fixed) != 0)
3032 buf[num_digits - 1] =
static_cast<char>(
'0' + digit);
3036 template <typename Float, FMT_ENABLE_IF(!is_double_double<Float>::value)>
3037 FMT_CONSTEXPR20
void format_hexfloat(Float value, format_specs specs,
3038 buffer<char>& buf) {
3041 static_assert(!std::is_same<Float, float>::value,
"");
3043 using info = dragonbox::float_info<Float>;
3046 using carrier_uint =
typename info::carrier_uint;
3048 const auto num_float_significand_bits = detail::num_significand_bits<Float>();
3050 basic_fp<carrier_uint> f(value);
3051 f.e += num_float_significand_bits;
3052 if (!has_implicit_bit<Float>()) --f.e;
3054 const auto num_fraction_bits =
3055 num_float_significand_bits + (has_implicit_bit<Float>() ? 1 : 0);
3056 const auto num_xdigits = (num_fraction_bits + 3) / 4;
3058 const auto leading_shift = ((num_xdigits - 1) * 4);
3059 const auto leading_mask = carrier_uint(0xF) << leading_shift;
3060 const auto leading_xdigit =
3061 static_cast<uint32_t
>((f.f & leading_mask) >> leading_shift);
3062 if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1);
3064 int print_xdigits = num_xdigits - 1;
3065 if (specs.precision >= 0 && print_xdigits > specs.precision) {
3066 const int shift = ((print_xdigits - specs.precision - 1) * 4);
3067 const auto mask = carrier_uint(0xF) << shift;
3068 const auto v =
static_cast<uint32_t
>((f.f & mask) >> shift);
3071 const auto inc = carrier_uint(1) << (shift + 4);
3077 if (!has_implicit_bit<Float>()) {
3078 const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
3079 if ((f.f & implicit_bit) == implicit_bit) {
3085 print_xdigits = specs.precision;
3088 char xdigits[num_bits<carrier_uint>() / 4];
3089 detail::fill_n(xdigits,
sizeof(xdigits),
'0');
3090 format_base2e(4, xdigits, f.f, num_xdigits, specs.upper());
3093 while (print_xdigits > 0 && xdigits[print_xdigits] ==
'0') --print_xdigits;
3096 buf.push_back(specs.upper() ?
'X' :
'x');
3097 buf.push_back(xdigits[0]);
3098 if (specs.alt() || print_xdigits > 0 || print_xdigits < specs.precision)
3100 buf.append(xdigits + 1, xdigits + 1 + print_xdigits);
3101 for (; print_xdigits < specs.precision; ++print_xdigits) buf.push_back(
'0');
3103 buf.push_back(specs.upper() ?
'P' :
'p');
3108 abs_e =
static_cast<uint32_t
>(-f.e);
3111 abs_e =
static_cast<uint32_t
>(f.e);
3113 format_decimal<char>(appender(buf), abs_e, detail::count_digits(abs_e));
3116 template <typename Float, FMT_ENABLE_IF(is_double_double<Float>::value)>
3117 FMT_CONSTEXPR20
void format_hexfloat(Float value, format_specs specs,
3118 buffer<char>& buf) {
3119 format_hexfloat(static_cast<double>(value), specs, buf);
3122 constexpr
auto fractional_part_rounding_thresholds(
int index) -> uint32_t {
3129 return U
"\x9999999a\x828f5c29\x80418938\x80068db9\x8000a7c6\x800010c7" 3130 U
"\x800001ae\x8000002b"[index];
3133 template <
typename Float>
3134 FMT_CONSTEXPR20
auto format_float(Float value,
int precision,
3135 const format_specs& specs,
bool binary32,
3136 buffer<char>& buf) ->
int {
3138 static_assert(!std::is_same<Float, float>::value,
"");
3139 auto converted_value = convert_float(value);
3141 const bool fixed = specs.type() == presentation_type::fixed;
3143 if (precision <= 0 || !fixed) {
3147 buf.try_resize(to_unsigned(precision));
3148 fill_n(buf.data(), precision,
'0');
3153 bool use_dragon =
true;
3154 unsigned dragon_flags = 0;
3155 if (!is_fast_float<Float>() || is_constant_evaluated()) {
3156 const auto inv_log2_10 = 0.3010299956639812;
3157 using info = dragonbox::float_info<decltype(converted_value)>;
3158 const auto f = basic_fp<typename info::carrier_uint>(converted_value);
3163 auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10;
3164 exp =
static_cast<int>(e);
3166 dragon_flags = dragon::fixup;
3169 using info = dragonbox::float_info<double>;
3170 auto br = bit_cast<uint64_t>(
static_cast<double>(value));
3172 const uint64_t significand_mask =
3173 (
static_cast<uint64_t
>(1) << num_significand_bits<double>()) - 1;
3174 uint64_t significand = (br & significand_mask);
3175 int exponent =
static_cast<int>((br & exponent_mask<double>()) >>
3176 num_significand_bits<double>());
3178 if (exponent != 0) {
3179 exponent -= exponent_bias<double>() + num_significand_bits<double>();
3181 (
static_cast<uint64_t
>(1) << num_significand_bits<double>());
3185 FMT_ASSERT(significand != 0,
"zeros should not appear here");
3186 int shift = countl_zero(significand);
3187 FMT_ASSERT(shift >= num_bits<uint64_t>() - num_significand_bits<double>(),
3189 shift -= (num_bits<uint64_t>() - num_significand_bits<double>() - 2);
3190 exponent = (std::numeric_limits<double>::min_exponent -
3191 num_significand_bits<double>()) -
3193 significand <<= shift;
3198 const int k = info::kappa - dragonbox::floor_log10_pow2(exponent);
3200 const int beta = exponent + dragonbox::floor_log2_pow10(k);
3201 uint64_t first_segment;
3202 bool has_more_segments;
3203 int digits_in_the_first_segment;
3205 const auto r = dragonbox::umul192_upper128(
3206 significand << beta, dragonbox::get_cached_power(k));
3207 first_segment = r.high();
3208 has_more_segments = r.low() != 0;
3211 if (first_segment >= 1000000000000000000ULL) {
3212 digits_in_the_first_segment = 19;
3216 digits_in_the_first_segment = 18;
3217 first_segment *= 10;
3222 if (fixed) adjust_precision(precision, exp + digits_in_the_first_segment);
3226 if (digits_in_the_first_segment > precision) {
3229 if (precision <= 0) {
3230 exp += digits_in_the_first_segment;
3232 if (precision < 0) {
3238 if ((first_segment | static_cast<uint64_t>(has_more_segments)) >
3239 5000000000000000000ULL) {
3247 exp += digits_in_the_first_segment - precision;
3256 const uint32_t first_subsegment =
static_cast<uint32_t
>(
3257 dragonbox::umul128_upper64(first_segment, 7922816251426433760ULL) >>
3259 const uint64_t second_third_subsegments =
3260 first_segment - first_subsegment * 10000000000ULL;
3264 bool should_round_up;
3265 int number_of_digits_to_print = min_of(precision, 9);
3268 auto print_subsegment = [&](uint32_t subsegment,
char* buffer) {
3269 int number_of_digits_printed = 0;
3272 if ((number_of_digits_to_print & 1) != 0) {
3278 prod = ((subsegment *
static_cast<uint64_t
>(720575941)) >> 24) + 1;
3279 digits =
static_cast<uint32_t
>(prod >> 32);
3280 *buffer =
static_cast<char>(
'0' + digits);
3281 number_of_digits_printed++;
3291 prod = ((subsegment *
static_cast<uint64_t
>(450359963)) >> 20) + 1;
3292 digits =
static_cast<uint32_t
>(prod >> 32);
3293 write2digits(buffer, digits);
3294 number_of_digits_printed += 2;
3298 while (number_of_digits_printed < number_of_digits_to_print) {
3299 prod =
static_cast<uint32_t
>(prod) * static_cast<uint64_t>(100);
3300 digits =
static_cast<uint32_t
>(prod >> 32);
3301 write2digits(buffer + number_of_digits_printed, digits);
3302 number_of_digits_printed += 2;
3307 print_subsegment(first_subsegment, buf.data());
3311 if (precision <= 9) {
3325 if (precision < 9) {
3326 uint32_t fractional_part =
static_cast<uint32_t
>(prod);
3328 fractional_part >= fractional_part_rounding_thresholds(
3329 8 - number_of_digits_to_print) ||
3330 ((fractional_part >> 31) &
3331 ((digits & 1) | (second_third_subsegments != 0) |
3332 has_more_segments)) != 0;
3340 should_round_up = second_third_subsegments > 5000000000ULL ||
3341 (second_third_subsegments == 5000000000ULL &&
3342 ((digits & 1) != 0 || has_more_segments));
3351 const uint32_t second_subsegment =
3352 static_cast<uint32_t
>(dragonbox::umul128_upper64(
3353 second_third_subsegments, 1844674407370955162ULL));
3354 const uint32_t third_subsegment =
3355 static_cast<uint32_t
>(second_third_subsegments) -
3356 second_subsegment * 10;
3358 number_of_digits_to_print = precision - 9;
3359 print_subsegment(second_subsegment, buf.data() + 9);
3362 if (precision < 18) {
3366 uint32_t fractional_part =
static_cast<uint32_t
>(prod);
3368 fractional_part >= fractional_part_rounding_thresholds(
3369 8 - number_of_digits_to_print) ||
3370 ((fractional_part >> 31) &
3371 ((digits & 1) | (third_subsegment != 0) |
3372 has_more_segments)) != 0;
3379 should_round_up = third_subsegment > 5 ||
3380 (third_subsegment == 5 &&
3381 ((digits & 1) != 0 || has_more_segments));
3386 if (should_round_up) {
3387 ++buf[precision - 1];
3388 for (
int i = precision - 1; i > 0 && buf[i] >
'9'; --i) {
3395 buf[precision++] =
'0';
3400 buf.try_resize(to_unsigned(precision));
3405 exp += digits_in_the_first_segment - 1;
3409 auto f = basic_fp<uint128_t>();
3410 bool is_predecessor_closer = binary32 ? f.assign(static_cast<float>(value))
3411 : f.assign(converted_value);
3412 if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer;
3413 if (fixed) dragon_flags |= dragon::fixed;
3416 const int max_double_digits = 767;
3417 if (precision > max_double_digits) precision = max_double_digits;
3418 format_dragon(f, dragon_flags, precision, buf, exp);
3420 if (!fixed && !specs.alt()) {
3422 auto num_digits = buf.size();
3423 while (num_digits > 0 && buf[num_digits - 1] ==
'0') {
3427 buf.try_resize(num_digits);
3432 template <
typename Char,
typename OutputIt,
typename T,
3433 FMT_ENABLE_IF(is_floating_point<T>::value)>
3434 FMT_CONSTEXPR20
auto write(OutputIt out, T value, format_specs specs,
3435 locale_ref loc = {}) -> OutputIt {
3436 if (specs.localized() && write_loc(out, value, specs, loc))
return out;
3439 sign s = detail::signbit(value) ? sign::minus : specs.sign();
3441 if (!detail::isfinite(value))
3442 return write_nonfinite<Char>(out, detail::isnan(value), specs, s);
3444 if (specs.align() == align::numeric && s != sign::none) {
3445 *out++ = detail::getsign<Char>(s);
3447 if (specs.width != 0) --specs.width;
3450 const int exp_upper = detail::exp_upper<T>();
3451 int precision = specs.precision;
3452 if (precision < 0) {
3453 if (specs.type() != presentation_type::none) {
3455 }
else if (is_fast_float<T>::value && !is_constant_evaluated()) {
3457 auto dec = dragonbox::to_decimal(
static_cast<fast_float_t<T>
>(value));
3458 return write_float<Char>(out, dec, specs, s, exp_upper, loc);
3463 if (specs.type() == presentation_type::hexfloat) {
3464 if (s != sign::none) buffer.push_back(detail::getsign<char>(s));
3465 format_hexfloat(convert_float(value), specs, buffer);
3466 return write_bytes<Char, align::right>(out, {buffer.data(), buffer.size()},
3470 if (specs.type() == presentation_type::exp) {
3471 if (precision == max_value<int>())
3472 report_error(
"number is too big");
3475 if (specs.precision != 0) specs.set_alt();
3476 }
else if (specs.type() == presentation_type::fixed) {
3477 if (specs.precision != 0) specs.set_alt();
3478 }
else if (precision == 0) {
3481 int exp = format_float(convert_float(value), precision, specs,
3482 std::is_same<T, float>(), buffer);
3484 specs.precision = precision;
3485 auto f = big_decimal_fp{buffer.data(),
static_cast<int>(buffer.size()), exp};
3486 return write_float<Char>(out, f, specs, s, exp_upper, loc);
3489 template <
typename Char,
typename OutputIt,
typename T,
3490 FMT_ENABLE_IF(is_fast_float<T>::value)>
3491 FMT_CONSTEXPR20
auto write(OutputIt out, T value) -> OutputIt {
3492 if (is_constant_evaluated())
return write<Char>(out, value, format_specs());
3494 auto s = detail::signbit(value) ? sign::minus : sign::none;
3495 auto mask = exponent_mask<fast_float_t<T>>();
3496 if ((bit_cast<decltype(mask)>(value) & mask) == mask)
3497 return write_nonfinite<Char>(out, std::isnan(value), {}, s);
3499 auto dec = dragonbox::to_decimal(
static_cast<fast_float_t<T>
>(value));
3500 auto significand = dec.significand;
3501 int significand_size = count_digits(significand);
3502 int exponent = dec.exponent + significand_size - 1;
3503 if (use_fixed(exponent, detail::exp_upper<T>())) {
3504 return write_fixed<Char, fallback_digit_grouping<Char>>(
3505 out, dec, significand_size, Char(
'.'), {}, s);
3509 const char* prefix =
"e+";
3510 int abs_exponent = exponent;
3512 abs_exponent = -exponent;
3515 auto has_decimal_point = significand_size != 1;
3516 size_t size = std::is_pointer<OutputIt>::value
3518 : to_unsigned((s != sign::none ? 1 : 0) + significand_size +
3519 (has_decimal_point ? 1 : 0) +
3520 (abs_exponent >= 100 ? 5 : 4));
3521 if (
auto ptr = to_pointer<Char>(out, size)) {
3522 if (s != sign::none) *ptr++ = Char(
'-');
3523 if (has_decimal_point) {
3525 ptr = format_decimal<Char>(ptr, significand, significand_size + 1);
3529 *ptr++ =
static_cast<Char
>(
'0' + significand);
3531 if (std::is_same<Char, char>::value) {
3532 memcpy(ptr, prefix, 2);
3538 if (abs_exponent >= 100) {
3539 *ptr++ =
static_cast<Char
>(
'0' + abs_exponent / 100);
3540 abs_exponent %= 100;
3542 write2digits(ptr, static_cast<unsigned>(abs_exponent));
3543 return select<std::is_pointer<OutputIt>::value>(ptr + 2, out);
3545 auto it = reserve(out, size);
3546 if (s != sign::none) *it++ = Char(
'-');
3548 it = write_significand(it, significand, significand_size, 1,
3549 has_decimal_point ? Char(
'.') : Char());
3551 it = write_exponent<Char>(exponent, it);
3552 return base_iterator(out, it);
3555 template <
typename Char,
typename OutputIt,
typename T,
3556 FMT_ENABLE_IF(is_floating_point<T>::value &&
3557 !is_fast_float<T>::value)>
3558 inline auto write(OutputIt out, T value) -> OutputIt {
3559 return write<Char>(out, value, {});
3562 template <
typename Char,
typename OutputIt>
3563 auto write(OutputIt out, monostate, format_specs = {}, locale_ref = {})
3565 FMT_ASSERT(
false,
"");
3569 template <
typename Char,
typename OutputIt>
3572 return copy_noinline<Char>(value.begin(), value.end(), out);
3575 template <
typename Char,
typename OutputIt,
typename T,
3576 FMT_ENABLE_IF(has_to_string_view<T>::value)>
3577 constexpr
auto write(OutputIt out,
const T& value) -> OutputIt {
3578 return write<Char>(out, to_string_view(value));
3583 typename Char,
typename OutputIt,
typename T,
3584 bool check = std::is_enum<T>::value && !std::is_same<T, Char>::value &&
3585 mapped_type_constant<T, Char>::value != type::custom_type,
3586 FMT_ENABLE_IF(check)>
3587 FMT_CONSTEXPR
auto write(OutputIt out, T value) -> OutputIt {
3588 return write<Char>(out,
static_cast<underlying_t<T>
>(value));
3591 template <
typename Char,
typename OutputIt,
typename T,
3592 FMT_ENABLE_IF(std::is_same<T, bool>::value)>
3593 FMT_CONSTEXPR
auto write(OutputIt out, T value,
const format_specs& specs = {},
3594 locale_ref = {}) -> OutputIt {
3595 return specs.type() != presentation_type::none &&
3596 specs.type() != presentation_type::string
3597 ? write<Char>(out, value ? 1 : 0, specs, {})
3598 : write_bytes<Char>(out, value ?
"true" :
"false", specs);
3601 template <
typename Char,
typename OutputIt>
3602 FMT_CONSTEXPR
auto write(OutputIt out, Char value) -> OutputIt {
3603 auto it = reserve(out, 1);
3605 return base_iterator(out, it);
3608 template <
typename Char,
typename OutputIt>
3609 FMT_CONSTEXPR20
auto write(OutputIt out,
const Char* value) -> OutputIt {
3611 report_error(
"string pointer is null");
3615 template <
typename Char,
typename OutputIt,
typename T,
3616 FMT_ENABLE_IF(std::is_same<T, void>::value)>
3617 auto write(OutputIt out,
const T* value,
const format_specs& specs = {},
3618 locale_ref = {}) -> OutputIt {
3619 return write_ptr<Char>(out, bit_cast<uintptr_t>(value), &specs);
3622 template <
typename Char,
typename OutputIt,
typename T,
3623 FMT_ENABLE_IF(mapped_type_constant<T, Char>::value ==
3624 type::custom_type &&
3625 !std::is_fundamental<T>::value)>
3626 FMT_CONSTEXPR
auto write(OutputIt out,
const T& value) -> OutputIt {
3627 auto f = formatter<T, Char>();
3630 auto ctx = basic_format_context<OutputIt, Char>(out, {}, {});
3631 return f.format(value, ctx);
3634 template <
typename T>
3636 bool_constant<std::is_same<T, int>::value || FMT_BUILTIN_TYPES>;
3640 template <
typename Char>
struct default_arg_formatter {
3641 using context = buffered_context<Char>;
3643 basic_appender<Char> out;
3645 void operator()(monostate) { report_error(
"argument not found"); }
3647 template <typename T, FMT_ENABLE_IF(is_builtin<T>::value)>
3648 void operator()(T value) {
3649 write<Char>(out, value);
3652 template <typename T, FMT_ENABLE_IF(!is_builtin<T>::value)>
3653 void operator()(T) {
3654 FMT_ASSERT(
false,
"");
3657 void operator()(
typename basic_format_arg<context>::handle h) {
3660 auto format_ctx = context(out, {}, {});
3661 h.format(parse_ctx, format_ctx);
3665 template <
typename Char>
struct arg_formatter {
3666 basic_appender<Char> out;
3667 const format_specs& specs;
3668 FMT_NO_UNIQUE_ADDRESS locale_ref locale;
3670 template <typename T, FMT_ENABLE_IF(is_builtin<T>::value)>
3671 FMT_CONSTEXPR FMT_INLINE
void operator()(T value) {
3672 detail::write<Char>(out, value, specs, locale);
3675 template <typename T, FMT_ENABLE_IF(!is_builtin<T>::value)>
3676 void operator()(T) {
3677 FMT_ASSERT(
false,
"");
3680 void operator()(
typename basic_format_arg<buffered_context<Char>>::handle) {
3686 struct dynamic_spec_getter {
3687 template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
3688 FMT_CONSTEXPR
auto operator()(T value) ->
unsigned long long {
3689 return is_negative(value) ? ~0ull :
static_cast<unsigned long long>(value);
3692 template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
3693 FMT_CONSTEXPR
auto operator()(T) ->
unsigned long long {
3694 report_error(
"width/precision is not integer");
3699 template <
typename Context>
3700 FMT_CONSTEXPR
void handle_dynamic_spec(
3701 arg_id_kind kind,
int& value,
3702 const arg_ref<typename Context::char_type>& ref, Context& ctx) {
3703 if (kind == arg_id_kind::none)
return;
3705 kind == arg_id_kind::index ? ctx.arg(ref.index) : ctx.arg(ref.name);
3706 if (!arg) report_error(
"argument not found");
3707 unsigned long long result = arg.visit(dynamic_spec_getter());
3708 if (result > to_unsigned(max_value<int>()))
3709 report_error(
"width/precision is out of range");
3710 value =
static_cast<int>(result);
3713 #if FMT_USE_NONTYPE_TEMPLATE_ARGS 3714 template <
typename T,
typename Char,
size_t N,
3715 fmt::detail::fixed_string<Char, N> Str>
3716 struct static_named_arg : view {
3717 static constexpr
auto name = Str.data;
3720 static_named_arg(
const T& v) : value(v) {}
3723 template <
typename T,
typename Char,
size_t N,
3724 fmt::detail::fixed_string<Char, N> Str>
3725 struct is_named_arg<static_named_arg<T, Char, N, Str>> : std::true_type {};
3727 template <
typename T,
typename Char,
size_t N,
3728 fmt::detail::fixed_string<Char, N> Str>
3729 struct is_static_named_arg<static_named_arg<T, Char, N, Str>> : std::true_type {
3732 template <
typename Char,
size_t N, fmt::detail::fixed_
string<Char, N> Str>
3734 template <
typename T>
auto operator=(T&& value)
const {
3735 return static_named_arg<T, Char, N, Str>(std::forward<T>(value));
3739 template <
typename Char>
struct udl_arg {
3742 template <
typename T>
auto operator=(T&& value)
const -> named_arg<Char, T> {
3743 return {str, std::forward<T>(value)};
3746 #endif // FMT_USE_NONTYPE_TEMPLATE_ARGS 3748 template <
typename Char =
char>
struct format_handler {
3750 buffered_context<Char> ctx;
3752 void on_text(
const Char* begin,
const Char* end) {
3753 copy_noinline<Char>(begin, end, ctx.out());
3756 FMT_CONSTEXPR
auto on_arg_id() ->
int {
return parse_ctx.next_arg_id(); }
3757 FMT_CONSTEXPR
auto on_arg_id(
int id) ->
int {
3758 parse_ctx.check_arg_id(
id);
3762 parse_ctx.check_arg_id(
id);
3763 int arg_id = ctx.arg_id(
id);
3764 if (arg_id < 0) report_error(
"argument not found");
3768 FMT_INLINE
void on_replacement_field(
int id,
const Char*) {
3769 ctx.arg(
id).visit(default_arg_formatter<Char>{ctx.out()});
3772 auto on_format_specs(
int id,
const Char* begin,
const Char* end)
3774 auto arg = ctx.arg(
id);
3775 if (!arg) report_error(
"argument not found");
3777 if (arg.format_custom(begin, parse_ctx, ctx))
return parse_ctx.begin();
3779 auto specs = dynamic_format_specs<Char>();
3780 begin = parse_format_specs(begin, end, specs, parse_ctx, arg.type());
3781 if (specs.dynamic()) {
3782 handle_dynamic_spec(specs.dynamic_width(), specs.width, specs.width_ref,
3784 handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
3785 specs.precision_ref, ctx);
3788 arg.visit(arg_formatter<Char>{ctx.out(), specs, ctx.locale()});
3792 FMT_NORETURN
void on_error(
const char* message) { report_error(message); }
3797 FMT_API
void do_report_error(format_func func,
int error_code,
3798 const char* message) noexcept;
3800 FMT_API
void format_error_code(buffer<char>& out,
int error_code,
3803 template <
typename T,
typename Char, type TYPE>
3804 template <
typename FormatContext>
3805 FMT_CONSTEXPR
auto native_formatter<T, Char, TYPE>::format(
3806 const T& val, FormatContext& ctx)
const -> decltype(ctx.out()) {
3807 if (!specs_.dynamic())
3808 return write<Char>(ctx.out(), val, specs_, ctx.locale());
3809 auto specs = format_specs(specs_);
3810 handle_dynamic_spec(specs.dynamic_width(), specs.width, specs_.width_ref,
3812 handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
3813 specs_.precision_ref, ctx);
3814 return write<Char>(ctx.out(), val, specs, ctx.locale());
3823 template <
typename OutputIt,
typename Char>
class generic_context {
3830 using char_type = Char;
3831 using iterator = OutputIt;
3832 enum { builtin_types = FMT_BUILTIN_TYPES };
3834 constexpr generic_context(OutputIt out,
3836 locale_ref loc = {})
3837 : out_(out), args_(args), loc_(loc) {}
3838 generic_context(generic_context&&) =
default;
3839 generic_context(
const generic_context&) =
delete;
3840 void operator=(
const generic_context&) =
delete;
3842 constexpr
auto arg(
int id)
const -> basic_format_arg<generic_context> {
3843 return args_.
get(
id);
3846 -> basic_format_arg<generic_context> {
3847 return args_.
get(name);
3850 return args_.get_id(name);
3853 constexpr
auto out()
const -> iterator {
return out_; }
3855 void advance_to(iterator it) {
3856 if (!detail::is_back_insert_iterator<iterator>()) out_ = it;
3859 constexpr
auto locale()
const -> locale_ref {
return loc_; }
3864 basic_format_arg<context> value_;
3867 template <typename T, FMT_ENABLE_IF(!detail::is_float128<T>::value)>
3868 loc_value(T value) : value_(value) {}
3870 template <typename T, FMT_ENABLE_IF(detail::is_float128<T>::value)>
3873 template <
typename Visitor>
auto visit(Visitor&& vis) -> decltype(vis(0)) {
3874 return value_.visit(vis);
3880 template <
typename Locale>
class format_facet :
public Locale::facet {
3882 std::string separator_;
3883 std::string grouping_;
3884 std::string decimal_point_;
3887 virtual auto do_put(appender out, loc_value val,
3888 const format_specs& specs)
const -> bool;
3891 static FMT_API
typename Locale::id id;
3893 explicit format_facet(Locale& loc);
3894 explicit format_facet(
string_view sep =
"", std::string grouping =
"\3",
3895 std::string decimal_point =
".")
3896 : separator_(sep.data(), sep.size()),
3897 grouping_(grouping),
3898 decimal_point_(decimal_point) {}
3900 auto put(appender out, loc_value val,
const format_specs& specs)
const 3902 return do_put(out, val, specs);
3906 #define FMT_FORMAT_AS(Type, Base) \ 3907 template <typename Char> \ 3908 struct formatter<Type, Char> : formatter<Base, Char> { \ 3909 template <typename FormatContext> \ 3910 FMT_CONSTEXPR auto format(Type value, FormatContext& ctx) const \ 3911 -> decltype(ctx.out()) { \ 3912 return formatter<Base, Char>::format(value, ctx); \ 3916 FMT_FORMAT_AS(
signed char,
int);
3917 FMT_FORMAT_AS(
unsigned char,
unsigned);
3918 FMT_FORMAT_AS(
short,
int);
3919 FMT_FORMAT_AS(
unsigned short,
unsigned);
3920 FMT_FORMAT_AS(
long, detail::long_type);
3921 FMT_FORMAT_AS(
unsigned long, detail::ulong_type);
3922 FMT_FORMAT_AS(Char*,
const Char*);
3924 FMT_FORMAT_AS(std::nullptr_t,
const void*);
3925 FMT_FORMAT_AS(
void*,
const void*);
3927 template <
typename Char,
size_t N>
3928 struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> {};
3930 template <
typename Char,
typename Traits,
typename Allocator>
3931 class formatter<std::basic_string<Char, Traits, Allocator>, Char>
3932 :
public formatter<basic_string_view<Char>, Char> {};
3934 template <
int N,
typename Char>
3935 struct formatter<detail::bitint<N>, Char> : formatter<long long, Char> {};
3936 template <
int N,
typename Char>
3937 struct formatter<detail::ubitint<N>, Char>
3938 : formatter<unsigned long long, Char> {};
3940 template <
typename Char>
3941 struct formatter<detail::float128, Char>
3942 : detail::native_formatter<detail::float128, Char,
3943 detail::type::float_type> {};
3945 template <
typename T,
typename Char>
3946 struct formatter<T, Char, void_t<detail::format_as_result<T>>>
3947 : formatter<detail::format_as_result<T>, Char> {
3948 template <
typename FormatContext>
3949 FMT_CONSTEXPR
auto format(
const T& value, FormatContext& ctx)
const 3950 -> decltype(ctx.out()) {
3951 auto&& val = format_as(value);
3952 return formatter<detail::format_as_result<T>, Char>::format(val, ctx);
3963 template <
typename T>
auto ptr(T p) ->
const void* {
3964 static_assert(std::is_pointer<T>::value,
"fmt::ptr used with non-pointer");
3965 return detail::bit_cast<
const void*>(p);
3976 template <
typename Enum>
3977 constexpr
auto underlying(Enum e) noexcept -> underlying_t<Enum> {
3978 return static_cast<underlying_t<Enum>
>(e);
3982 template <typename Enum, FMT_ENABLE_IF(std::is_enum<Enum>::value)>
3983 constexpr
auto format_as(Enum e) noexcept -> underlying_t<Enum> {
3984 return static_cast<underlying_t<Enum>
>(e);
3988 #ifdef __cpp_lib_byte 3989 template <
typename Char>
3990 struct formatter<std::byte, Char> : formatter<unsigned, Char> {
3991 static auto format_as(std::byte b) ->
unsigned char {
3992 return static_cast<unsigned char>(b);
3994 template <
typename Context>
3995 auto format(std::byte b, Context& ctx)
const -> decltype(ctx.out()) {
3996 return formatter<unsigned, Char>::format(format_as(b), ctx);
4007 template <>
struct formatter<bytes> {
4009 detail::dynamic_format_specs<> specs_;
4013 return parse_format_specs(ctx.
begin(), ctx.
end(), specs_, ctx,
4014 detail::type::string_type);
4017 template <
typename FormatContext>
4018 auto format(bytes b, FormatContext& ctx)
const -> decltype(ctx.out()) {
4019 auto specs = specs_;
4020 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
4021 specs.width_ref, ctx);
4022 detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
4023 specs.precision_ref, ctx);
4024 return detail::write_bytes<char>(ctx.out(), b.data, specs);
4029 template <
typename T>
struct group_digits_view {
4042 template <
typename T>
auto group_digits(T value) -> group_digits_view<T> {
4046 template <
typename T>
struct formatter<group_digits_view<T>> : formatter<T> {
4048 detail::dynamic_format_specs<> specs_;
4052 return parse_format_specs(ctx.
begin(), ctx.
end(), specs_, ctx,
4053 detail::type::int_type);
4056 template <
typename FormatContext>
4057 auto format(group_digits_view<T> view, FormatContext& ctx)
const 4058 -> decltype(ctx.out()) {
4059 auto specs = specs_;
4060 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
4061 specs.width_ref, ctx);
4062 detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
4063 specs.precision_ref, ctx);
4064 auto arg = detail::make_write_int_arg(view.value, specs.sign());
4065 return detail::write_int(
4066 ctx.out(),
static_cast<detail::uint64_or_128_t<T>
>(arg.abs_value),
4067 arg.prefix, specs, detail::digit_grouping<char>(
"\3",
","));
4071 template <
typename T,
typename Char>
struct nested_view {
4072 const formatter<T, Char>* fmt;
4076 template <
typename T,
typename Char>
4077 struct formatter<nested_view<T, Char>, Char> {
4081 template <
typename FormatContext>
4082 auto format(nested_view<T, Char> view, FormatContext& ctx)
const 4083 -> decltype(ctx.out()) {
4084 return view.fmt->format(*view.value, ctx);
4088 template <
typename T,
typename Char =
char>
struct nested_formatter {
4092 formatter<T, Char> formatter_;
4095 constexpr nested_formatter() : width_(0) {}
4098 auto it = ctx.
begin(), end = ctx.
end();
4099 if (it == end)
return it;
4100 auto specs = format_specs();
4101 it = detail::parse_align(it, end, specs);
4104 auto width_ref = detail::arg_ref<Char>();
4105 if ((c >=
'0' && c <=
'9') || c ==
'{') {
4106 it = detail::parse_width(it, end, specs, width_ref, ctx);
4107 width_ = specs.width;
4110 return formatter_.parse(ctx);
4113 template <
typename FormatContext,
typename F>
4114 auto write_padded(FormatContext& ctx, F write)
const -> decltype(ctx.out()) {
4115 if (width_ == 0)
return write(ctx.out());
4117 write(basic_appender<Char>(buf));
4118 auto specs = format_specs();
4119 specs.width = width_;
4120 specs.copy_fill_from(specs_);
4121 specs.set_align(specs_.align());
4122 return detail::write<Char>(
4126 auto nested(
const T& value)
const -> nested_view<T, Char> {
4127 return nested_view<T, Char>{&formatter_, &value};
4132 #if FMT_USE_NONTYPE_TEMPLATE_ARGS 4133 template <detail::fixed_
string S> constexpr
auto operator""_a() {
4134 using char_t = remove_cvref_t<decltype(*S.data)>;
4135 return detail::udl_arg<char_t,
sizeof(S.data) /
sizeof(char_t), S>();
4146 constexpr
auto operator""_a(
const char* s,
size_t) -> detail::udl_arg<char> {
4149 #endif // FMT_USE_NONTYPE_TEMPLATE_ARGS 4157 enum { buffer_size = std::numeric_limits<unsigned long long>::digits10 + 3 };
4158 mutable char buffer_[buffer_size];
4161 template <
typename UInt>
4162 FMT_CONSTEXPR20
auto format_unsigned(UInt value) ->
char* {
4163 auto n =
static_cast<detail::uint32_or_64_or_128_t<UInt>
>(value);
4164 return detail::do_format_decimal(buffer_, n, buffer_size - 1);
4167 template <
typename Int>
4168 FMT_CONSTEXPR20
auto format_signed(Int value) ->
char* {
4169 auto abs_value =
static_cast<detail::uint32_or_64_or_128_t<Int>
>(value);
4170 bool negative = value < 0;
4171 if (negative) abs_value = 0 - abs_value;
4172 auto begin = format_unsigned(abs_value);
4173 if (negative) *--begin =
'-';
4178 FMT_CONSTEXPR20
explicit format_int(
int value) : str_(format_signed(value)) {}
4179 FMT_CONSTEXPR20
explicit format_int(
long value)
4180 : str_(format_signed(value)) {}
4181 FMT_CONSTEXPR20
explicit format_int(
long long value)
4182 : str_(format_signed(value)) {}
4183 FMT_CONSTEXPR20
explicit format_int(
unsigned value)
4184 : str_(format_unsigned(value)) {}
4185 FMT_CONSTEXPR20
explicit format_int(
unsigned long value)
4186 : str_(format_unsigned(value)) {}
4187 FMT_CONSTEXPR20
explicit format_int(
unsigned long long value)
4188 : str_(format_unsigned(value)) {}
4191 FMT_CONSTEXPR20
auto size() const ->
size_t {
4192 return detail::to_unsigned(buffer_ - str_ + buffer_size - 1);
4197 FMT_CONSTEXPR20
auto data() const -> const
char* {
return str_; }
4201 FMT_CONSTEXPR20
auto c_str() const -> const
char* {
4202 buffer_[buffer_size - 1] =
'\0';
4207 inline auto str() const -> std::
string {
return {str_, size()}; }
4210 #if FMT_CLANG_ANALYZER 4211 # define FMT_STRING_IMPL(s, base) s 4213 # define FMT_STRING_IMPL(s, base) \ 4217 struct FMT_VISIBILITY("hidden") FMT_COMPILE_STRING : base { \ 4218 using char_type = fmt::remove_cvref_t<decltype(s[0])>; \ 4219 constexpr explicit operator fmt::basic_string_view<char_type>() \ 4221 return fmt::detail::compile_string_to_view<char_type>(s); \ 4224 using FMT_STRING_VIEW = \ 4225 fmt::basic_string_view<typename FMT_COMPILE_STRING::char_type>; \ 4226 fmt::detail::ignore_unused(FMT_STRING_VIEW(FMT_COMPILE_STRING())); \ 4227 return FMT_COMPILE_STRING(); \ 4229 #endif // FMT_CLANG_ANALYZER 4239 #define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string) 4242 -> std::system_error;
4259 template <
typename... T>
4260 auto system_error(
int error_code, format_string<T...> fmt, T&&... args)
4261 -> std::system_error {
4262 return vsystem_error(error_code, fmt.str, vargs<T...>{{args...}});
4279 const char* message) noexcept;
4283 FMT_API
void report_system_error(
int error_code,
const char* message) noexcept;
4288 detail::vformat_to(buf, fmt, args, loc);
4289 return {buf.data(), buf.size()};
4292 template <
typename... T>
4293 FMT_INLINE
auto format(locale_ref loc, format_string<T...> fmt, T&&... args)
4295 return vformat(loc, fmt.str, vargs<T...>{{args...}});
4298 template <
typename OutputIt,
4299 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
4302 auto&& buf = detail::get_buffer<char>(out);
4303 detail::vformat_to(buf, fmt, args, loc);
4304 return detail::get_iterator(buf, out);
4307 template <
typename OutputIt,
typename... T,
4308 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
4309 FMT_INLINE
auto format_to(OutputIt out, locale_ref loc, format_string<T...> fmt,
4310 T&&... args) -> OutputIt {
4311 return fmt::vformat_to(out, loc, fmt.str, vargs<T...>{{args...}});
4314 template <
typename... T>
4315 FMT_NODISCARD FMT_INLINE
auto formatted_size(locale_ref loc,
4316 format_string<T...> fmt,
4317 T&&... args) ->
size_t {
4318 auto buf = detail::counting_buffer<>();
4319 detail::vformat_to(buf, fmt.str, vargs<T...>{{args...}}, loc);
4334 template <
typename... T>
4335 FMT_NODISCARD FMT_INLINE
auto format(format_string<T...> fmt, T&&... args)
4337 return vformat(fmt.str, vargs<T...>{{args...}});
4347 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
4348 FMT_NODISCARD FMT_CONSTEXPR_STRING
auto to_string(T value) -> std::string {
4351 char buffer[max_of(detail::digits10<T>() + 2, 5)];
4352 return {buffer, detail::write<char>(buffer, value)};
4355 template <typename T, FMT_ENABLE_IF(detail::use_format_as<T>::value)>
4356 FMT_NODISCARD FMT_CONSTEXPR_STRING
auto to_string(
const T& value)
4358 return to_string(format_as(value));
4361 template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value &&
4362 !detail::use_format_as<T>::value)>
4363 FMT_NODISCARD FMT_CONSTEXPR_STRING
auto to_string(
const T& value)
4366 detail::write<char>(appender(buffer), value);
4367 return {buffer.data(), buffer.size()};
4373 #ifdef FMT_HEADER_ONLY 4374 # define FMT_FUNC inline 4375 # include "format-inl.h" 4379 #ifdef FMT_REMOVE_TRANSITIVE_INCLUDES 4380 # undef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES 4383 #endif // FMT_FORMAT_H_ A dynamically growing memory buffer for trivially copyable/constructible types with the first SIZE el...
Definition: format.h:785
void reserve(size_t new_capacity)
Increases the buffer capacity to new_capacity.
Definition: format.h:898
void info(const STRING &string, const int verbosity_level=1)
Use this function for writing informational messages.
Definition: info.h:51
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition: base.h:623
constexpr auto data() const noexcept -> const Char *
Returns a pointer to the string data.
Definition: base.h:557
FMT_CONSTEXPR void clear()
Clears this buffer.
Definition: base.h:1815
constexpr auto size() const noexcept -> size_t
Returns the string size.
Definition: base.h:560
FMT_CONSTEXPR void set(T *buf_data, size_t buf_capacity) noexcept
Sets the buffer data and capacity.
Definition: base.h:1786
Converts a string literal into a format string that will be parsed at compile time and converted into...
Definition: args.h:20
An implementation of std::basic_string_view for pre-C++17.
Definition: base.h:515
constexpr auto end() const noexcept -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition: base.h:872
constexpr auto size() const noexcept -> size_t
Returns the size of this buffer.
Definition: base.h:1805
constexpr auto capacity() const noexcept -> size_t
Returns the capacity of this buffer.
Definition: base.h:1808
NUMBER square(const NUMBER &x)
returns the square of a number, templated.
Definition: common.h:154
FMT_CONSTEXPR auto data() noexcept -> T *
Returns a pointer to the buffer data (not null-terminated).
Definition: base.h:1811
Definition: format.h:4131
constexpr auto begin() const noexcept -> iterator
Returns an iterator to the beginning of the format string range being parsed.
Definition: base.h:869
void error(const char *const s,...)
Print error with format string a la printf and throw exception.
Definition: error.cxx:42
FMT_CONSTEXPR void resize(size_t count)
Resizes the buffer to contain count elements. If T is a POD type new elements may not be initialized...
Definition: format.h:895
bool next(BasicCoordinate< num_dimensions, int > &indices, const Array< num_dimensions2, T > &a)
Given an index into an array, increment it to the next one.
Definition: array_index_functions.inl:107
Definition: format.h:3981
FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer &&other) noexcept
Constructs a basic_memory_buffer object moving the content of the other object to it...
Definition: format.h:877
A contiguous memory buffer with an optional growing ability. It is an internal class and shouldn't be...
Definition: base.h:1763
auto operator=(basic_memory_buffer &&other) noexcept -> basic_memory_buffer &
Moves the content of the other basic_memory_buffer object to this one.
Definition: format.h:883
elemT sum(IterT start, IterT end, elemT init)
Compute the sum of a sequence using operator+=(), using an initial value.
Definition: more_algorithms.inl:52
FMT_CONSTEXPR void advance_to(iterator it)
Advances the begin iterator to it.
Definition: base.h:875