36#ifndef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES
37# define _LIBCPP_REMOVE_TRANSITIVE_INCLUDES
38# define FMT_REMOVE_TRANSITIVE_INCLUDES
47# include <initializer_list>
49# if defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI)
55# include <system_error>
58# if FMT_HAS_INCLUDE(<bit>) && FMT_CPLUSPLUS > 201703L
63# if FMT_HAS_INCLUDE(<string_view>) && \
64 (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION))
65# include <string_view>
66# define FMT_USE_STRING_VIEW
70#if defined __cpp_inline_variables && __cpp_inline_variables >= 201606L
71# define FMT_INLINE_VARIABLE inline
73# define FMT_INLINE_VARIABLE
76#ifndef FMT_NO_UNIQUE_ADDRESS
77# if FMT_CPLUSPLUS >= 202002L
78# if FMT_HAS_CPP_ATTRIBUTE(no_unique_address)
79# define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]]
81# elif (FMT_MSC_VERSION >= 1929) && !FMT_CLANG_VERSION
82# define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
86#ifndef FMT_NO_UNIQUE_ADDRESS
87# define FMT_NO_UNIQUE_ADDRESS
91#if defined(FMT_LIB_EXPORT) || defined(FMT_SHARED)
92# define FMT_SO_VISIBILITY(value) FMT_VISIBILITY(value)
94# define FMT_SO_VISIBILITY(value)
98# define FMT_HAS_BUILTIN(x) __has_builtin(x)
100# define FMT_HAS_BUILTIN(x) 0
103#if FMT_GCC_VERSION || FMT_CLANG_VERSION
104# define FMT_NOINLINE __attribute__((noinline))
110template <>
struct iterator_traits<fmt::appender> {
111 using iterator_category = output_iterator_tag;
112 using value_type = char;
118# if FMT_MSC_VERSION || defined(__NVCC__)
121template <
typename Exception>
inline void do_throw(
const Exception& x) {
124 volatile bool b =
true;
129# define FMT_THROW(x) detail::do_throw(x)
131# define FMT_THROW(x) throw x
134# define FMT_THROW(x) \
135 ::fmt::detail::assert_fail(__FILE__, __LINE__, (x).what())
139#ifndef FMT_MAYBE_UNUSED
140# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused)
141# define FMT_MAYBE_UNUSED [[maybe_unused]]
143# define FMT_MAYBE_UNUSED
147#ifndef FMT_USE_USER_DEFINED_LITERALS
152# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 409 || \
153 FMT_MSC_VERSION >= 1900) && \
154 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 480)
155# define FMT_USE_USER_DEFINED_LITERALS 1
157# define FMT_USE_USER_DEFINED_LITERALS 0
165#if !defined(FMT_REDUCE_INT_INSTANTIATIONS)
166# define FMT_REDUCE_INT_INSTANTIATIONS 0
172# if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION
173# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
175# if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION
176# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
183# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION || \
184 defined(__NVCOMPILER)
185# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n)
187# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || \
188 FMT_ICC_VERSION || defined(__NVCOMPILER)
189# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n)
200#if FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) && \
201 !defined(FMT_BUILTIN_CTZLL)
205# if !defined(__clang__)
206# pragma intrinsic(_BitScanForward)
207# pragma intrinsic(_BitScanReverse)
209# pragma intrinsic(_BitScanForward64)
210# pragma intrinsic(_BitScanReverse64)
214inline auto clz(uint32_t x) ->
int {
216 _BitScanReverse(&r, x);
217 FMT_ASSERT(x != 0,
"");
221 FMT_MSC_WARNING(suppress : 6102)
222 return 31 ^
static_cast<int>(r);
224# define FMT_BUILTIN_CLZ(n) detail::clz(n)
226inline auto clzll(uint64_t x) ->
int {
229 _BitScanReverse64(&r, x);
232 if (_BitScanReverse(&r,
static_cast<uint32_t
>(x >> 32)))
233 return 63 ^
static_cast<int>(r + 32);
235 _BitScanReverse(&r,
static_cast<uint32_t
>(x));
237 FMT_ASSERT(x != 0,
"");
238 FMT_MSC_WARNING(suppress : 6102)
239 return 63 ^
static_cast<int>(r);
241# define FMT_BUILTIN_CLZLL(n) detail::clzll(n)
243inline auto ctz(uint32_t x) ->
int {
245 _BitScanForward(&r, x);
246 FMT_ASSERT(x != 0,
"");
247 FMT_MSC_WARNING(suppress : 6102)
248 return static_cast<int>(r);
250# define FMT_BUILTIN_CTZ(n) detail::ctz(n)
252inline auto ctzll(uint64_t x) ->
int {
254 FMT_ASSERT(x != 0,
"");
255 FMT_MSC_WARNING(suppress : 6102)
257 _BitScanForward64(&r, x);
260 if (_BitScanForward(&r,
static_cast<uint32_t
>(x)))
return static_cast<int>(r);
262 _BitScanForward(&r,
static_cast<uint32_t
>(x >> 32));
265 return static_cast<int>(r);
267# define FMT_BUILTIN_CTZLL(n) detail::ctzll(n)
274template <
typename Char,
typename Traits,
typename Allocator>
280FMT_CONSTEXPR
inline void abort_fuzzing_if(
bool condition) {
281 ignore_unused(condition);
283 if (condition)
throw std::runtime_error(
"fuzzing limit reached");
287#if defined(FMT_USE_STRING_VIEW)
288template <
typename Char>
using std_string_view = std::basic_string_view<Char>;
294template <
typename To,
typename From, FMT_ENABLE_IF(sizeof(To) == sizeof(From))>
295FMT_CONSTEXPR20
auto bit_cast(
const From& from) -> To {
296#ifdef __cpp_lib_bit_cast
297 if (is_constant_evaluated())
return std::bit_cast<To>(from);
301 std::memcpy(
static_cast<void*
>(&to), &from,
sizeof(to));
305inline auto is_big_endian() ->
bool {
308#elif defined(__BIG_ENDIAN__)
310#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
311 return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;
314 char data[
sizeof(int)];
316 return bit_cast<bytes>(1).data[0] == 0;
320class uint128_fallback {
325 constexpr uint128_fallback(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {}
326 constexpr uint128_fallback(uint64_t
value = 0) : lo_(
value), hi_(0) {}
328 constexpr auto high()
const noexcept -> uint64_t {
return hi_; }
329 constexpr auto low()
const noexcept -> uint64_t {
return lo_; }
331 template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
332 constexpr explicit operator T()
const {
333 return static_cast<T
>(lo_);
336 friend constexpr auto operator==(
const uint128_fallback& lhs,
337 const uint128_fallback& rhs) ->
bool {
338 return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_;
340 friend constexpr auto operator!=(
const uint128_fallback& lhs,
341 const uint128_fallback& rhs) ->
bool {
342 return !(lhs == rhs);
344 friend constexpr auto operator>(
const uint128_fallback& lhs,
345 const uint128_fallback& rhs) ->
bool {
346 return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_;
348 friend constexpr auto operator|(
const uint128_fallback& lhs,
349 const uint128_fallback& rhs)
350 -> uint128_fallback {
351 return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_};
353 friend constexpr auto operator&(
const uint128_fallback& lhs,
354 const uint128_fallback& rhs)
355 -> uint128_fallback {
356 return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_};
358 friend constexpr auto operator~(
const uint128_fallback& n)
359 -> uint128_fallback {
360 return {~n.hi_, ~n.lo_};
362 friend auto operator+(
const uint128_fallback& lhs,
363 const uint128_fallback& rhs) -> uint128_fallback {
364 auto result = uint128_fallback(lhs);
368 friend auto operator*(
const uint128_fallback& lhs, uint32_t rhs)
369 -> uint128_fallback {
370 FMT_ASSERT(lhs.hi_ == 0,
"");
371 uint64_t hi = (lhs.lo_ >> 32) * rhs;
372 uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs;
373 uint64_t new_lo = (hi << 32) + lo;
374 return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo};
376 friend auto operator-(
const uint128_fallback& lhs, uint64_t rhs)
377 -> uint128_fallback {
378 return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs};
380 FMT_CONSTEXPR
auto operator>>(
int shift)
const -> uint128_fallback {
381 if (shift == 64)
return {0, hi_};
382 if (shift > 64)
return uint128_fallback(0, hi_) >> (shift - 64);
383 return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)};
385 FMT_CONSTEXPR
auto operator<<(
int shift)
const -> uint128_fallback {
386 if (shift == 64)
return {lo_, 0};
387 if (shift > 64)
return uint128_fallback(lo_, 0) << (shift - 64);
388 return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)};
390 FMT_CONSTEXPR
auto operator>>=(
int shift) -> uint128_fallback& {
391 return *
this = *
this >> shift;
393 FMT_CONSTEXPR
void operator+=(uint128_fallback n) {
394 uint64_t new_lo = lo_ + n.lo_;
395 uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0);
396 FMT_ASSERT(new_hi >= hi_,
"");
400 FMT_CONSTEXPR
void operator&=(uint128_fallback n) {
405 FMT_CONSTEXPR20
auto operator+=(uint64_t n)
noexcept -> uint128_fallback& {
406 if (is_constant_evaluated()) {
408 hi_ += (lo_ < n ? 1 : 0);
411#if FMT_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__)
412 unsigned long long carry;
413 lo_ = __builtin_addcll(lo_, n, 0, &carry);
415#elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__)
416 unsigned long long result;
417 auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result);
420#elif defined(_MSC_VER) && defined(_M_X64)
421 auto carry = _addcarry_u64(0, lo_, n, &lo_);
422 _addcarry_u64(carry, hi_, 0, &hi_);
425 hi_ += (lo_ < n ? 1 : 0);
431using uint128_t = conditional_t<FMT_USE_INT128, uint128_opt, uint128_fallback>;
434using uintptr_t = ::uintptr_t;
436using uintptr_t = uint128_t;
441template <
typename T>
constexpr auto max_value() -> T {
442 return (std::numeric_limits<T>::max)();
444template <
typename T>
constexpr auto num_bits() ->
int {
445 return std::numeric_limits<T>::digits;
448template <>
constexpr auto num_bits<int128_opt>() ->
int {
return 128; }
449template <>
constexpr auto num_bits<uint128_opt>() ->
int {
return 128; }
450template <>
constexpr auto num_bits<uint128_fallback>() ->
int {
return 128; }
454template <
typename To,
typename From, FMT_ENABLE_IF(sizeof(To) >
sizeof(From))>
455inline auto bit_cast(
const From& from) -> To {
456 constexpr auto size =
static_cast<int>(
sizeof(From) /
sizeof(unsigned));
458 unsigned value[
static_cast<unsigned>(size)];
459 } data = bit_cast<data_t>(from);
461 if (const_check(is_big_endian())) {
462 for (
int i = 0; i < size; ++i)
463 result = (result << num_bits<unsigned>()) | data.value[i];
465 for (
int i = size - 1; i >= 0; --i)
466 result = (result << num_bits<unsigned>()) | data.value[i];
471template <
typename UInt>
472FMT_CONSTEXPR20
inline auto countl_zero_fallback(UInt n) ->
int {
474 constexpr UInt msb_mask =
static_cast<UInt
>(1) << (num_bits<UInt>() - 1);
475 for (; (n & msb_mask) == 0; n <<= 1) lz++;
479FMT_CONSTEXPR20
inline auto countl_zero(uint32_t n) ->
int {
480#ifdef FMT_BUILTIN_CLZ
481 if (!is_constant_evaluated())
return FMT_BUILTIN_CLZ(n);
483 return countl_zero_fallback(n);
486FMT_CONSTEXPR20
inline auto countl_zero(uint64_t n) ->
int {
487#ifdef FMT_BUILTIN_CLZLL
488 if (!is_constant_evaluated())
return FMT_BUILTIN_CLZLL(n);
490 return countl_zero_fallback(n);
493FMT_INLINE
void assume(
bool condition) {
495#if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION
496 __builtin_assume(condition);
498 if (!condition) __builtin_unreachable();
504using iterator_t =
decltype(std::begin(std::declval<T&>()));
505template <
typename T>
using sentinel_t =
decltype(std::end(std::declval<T&>()));
508template <
typename Char>
509inline auto get_data(std::basic_string<Char>& s) -> Char* {
512template <
typename Container>
513inline auto get_data(Container& c) ->
typename Container::value_type* {
519template <
typename OutputIt,
521 is_contiguous<typename OutputIt::container>::value)>
522#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION
523__attribute__((no_sanitize(
"undefined")))
526reserve(OutputIt it,
size_t n) ->
typename OutputIt::value_type* {
527 auto& c = get_container(it);
528 size_t size = c.size();
530 return get_data(c) + size;
534inline auto reserve(basic_appender<T> it,
size_t n) -> basic_appender<T> {
536 buf.try_reserve(buf.size() + n);
540template <
typename Iterator>
541constexpr auto reserve(Iterator& it,
size_t) -> Iterator& {
545template <
typename OutputIt>
546using reserve_iterator =
547 remove_reference_t<decltype(reserve(std::declval<OutputIt&>(), 0))>;
549template <
typename T,
typename OutputIt>
550constexpr auto to_pointer(OutputIt,
size_t) -> T* {
553template <
typename T>
auto to_pointer(basic_appender<T> it,
size_t n) -> T* {
555 auto size = buf.size();
556 buf.try_reserve(size + n);
557 if (buf.capacity() < size + n)
return nullptr;
558 buf.try_resize(size + n);
559 return buf.data() + size;
562template <
typename OutputIt,
564 is_contiguous<typename OutputIt::container>::value)>
565inline auto base_iterator(OutputIt it,
566 typename OutputIt::container_type::value_type*)
571template <
typename Iterator>
572constexpr auto base_iterator(Iterator, Iterator it) -> Iterator {
578template <
typename OutputIt,
typename Size,
typename T>
579FMT_CONSTEXPR
auto fill_n(OutputIt out, Size count,
const T&
value)
581 for (Size i = 0; i < count; ++i) *out++ =
value;
584template <
typename T,
typename Size>
585FMT_CONSTEXPR20
auto fill_n(T* out, Size count,
char value) -> T* {
586 if (is_constant_evaluated()) {
587 return fill_n<T*, Size, T>(out, count,
value);
589 std::memset(out,
value, to_unsigned(count));
593template <
typename OutChar,
typename InputIt,
typename OutputIt>
594FMT_CONSTEXPR FMT_NOINLINE
auto copy_noinline(InputIt begin, InputIt end,
595 OutputIt out) -> OutputIt {
596 return copy<OutChar>(begin, end, out);
616FMT_CONSTEXPR
inline auto utf8_decode(
const char* s, uint32_t* c,
int* e)
618 constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
619 constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
620 constexpr const int shiftc[] = {0, 18, 12, 6, 0};
621 constexpr const int shifte[] = {0, 6, 4, 2, 0};
623 int len =
"\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4"
624 [
static_cast<unsigned char>(*s) >> 3];
628 const char* next = s + len + !len;
630 using uchar =
unsigned char;
634 *c = uint32_t(uchar(s[0]) & masks[len]) << 18;
635 *c |= uint32_t(uchar(s[1]) & 0x3f) << 12;
636 *c |= uint32_t(uchar(s[2]) & 0x3f) << 6;
637 *c |= uint32_t(uchar(s[3]) & 0x3f) << 0;
641 *e = (*c < mins[len]) << 6;
642 *e |= ((*c >> 11) == 0x1b) << 7;
643 *e |= (*c > 0x10FFFF) << 8;
644 *e |= (uchar(s[1]) & 0xc0) >> 2;
645 *e |= (uchar(s[2]) & 0xc0) >> 4;
646 *e |= uchar(s[3]) >> 6;
653constexpr FMT_INLINE_VARIABLE uint32_t invalid_code_point = ~uint32_t();
658FMT_CONSTEXPR
void for_each_codepoint(string_view s, F f) {
659 auto decode = [f](
const char* buf_ptr,
const char* ptr) {
660 auto cp = uint32_t();
662 auto end = utf8_decode(buf_ptr, &cp, &error);
663 bool result = f(error ? invalid_code_point : cp,
664 string_view(ptr, error ? 1 : to_unsigned(end - buf_ptr)));
665 return result ? (error ? buf_ptr + 1 : end) : nullptr;
668 const size_t block_size = 4;
669 if (s.
size() >= block_size) {
670 for (
auto end = p + s.
size() - block_size + 1; p < end;) {
675 if (
auto num_chars_left = s.
data() + s.
size() - p) {
676 char buf[2 * block_size - 1] = {};
677 copy<char>(p, p + num_chars_left, buf);
678 const char* buf_ptr = buf;
680 auto end = decode(buf_ptr, p);
684 }
while (buf_ptr - buf < num_chars_left);
688template <
typename Char>
689inline auto compute_width(basic_string_view<Char> s) ->
size_t {
694FMT_CONSTEXPR
inline auto compute_width(string_view s) ->
size_t {
695 size_t num_code_points = 0;
697 struct count_code_points {
699 FMT_CONSTEXPR
auto operator()(uint32_t cp, string_view)
const ->
bool {
700 *count += detail::to_unsigned(
707 (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) ||
708 (cp >= 0xac00 && cp <= 0xd7a3) ||
709 (cp >= 0xf900 && cp <= 0xfaff) ||
710 (cp >= 0xfe10 && cp <= 0xfe19) ||
711 (cp >= 0xfe30 && cp <= 0xfe6f) ||
712 (cp >= 0xff00 && cp <= 0xff60) ||
713 (cp >= 0xffe0 && cp <= 0xffe6) ||
714 (cp >= 0x20000 && cp <= 0x2fffd) ||
715 (cp >= 0x30000 && cp <= 0x3fffd) ||
717 (cp >= 0x1f300 && cp <= 0x1f64f) ||
719 (cp >= 0x1f900 && cp <= 0x1f9ff))));
724 for_each_codepoint(s, count_code_points{&num_code_points});
725 return num_code_points;
728template <
typename Char>
729inline auto code_point_index(basic_string_view<Char> s,
size_t n) ->
size_t {
730 size_t size = s.
size();
731 return n < size ? n : size;
735inline auto code_point_index(string_view s,
size_t n) ->
size_t {
736 size_t result = s.
size();
737 const char* begin = s.begin();
738 for_each_codepoint(s, [begin, &n, &result](uint32_t, string_view sv) {
743 result = to_unsigned(sv.begin() - begin);
755 std::integral_constant<bool, std::numeric_limits<T>::is_signed ||
756 std::is_same<T, int128_opt>::value>;
760 bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value &&
761 !std::is_same<T, char>::value &&
762 !std::is_same<T, wchar_t>::value>;
765# define FMT_USE_FLOAT 1
767#ifndef FMT_USE_DOUBLE
768# define FMT_USE_DOUBLE 1
770#ifndef FMT_USE_LONG_DOUBLE
771# define FMT_USE_LONG_DOUBLE 1
774#if defined(FMT_USE_FLOAT128)
776#elif FMT_CLANG_VERSION && FMT_HAS_INCLUDE(<quadmath.h>)
777# define FMT_USE_FLOAT128 1
778#elif FMT_GCC_VERSION && defined(_GLIBCXX_USE_FLOAT128) && \
779 !defined(__STRICT_ANSI__)
780# define FMT_USE_FLOAT128 1
782# define FMT_USE_FLOAT128 0
785using float128 = __float128;
787using float128 = void;
790template <
typename T>
using is_float128 = std::is_same<T, float128>;
793using is_floating_point =
794 bool_constant<std::is_floating_point<T>::value || is_float128<T>::value>;
796template <typename T, bool = std::is_floating_point<T>::value>
797struct is_fast_float : bool_constant<std::numeric_limits<T>::is_iec559 &&
798 sizeof(T) <= sizeof(double)> {};
799template <typename T> struct is_fast_float<T, false> : std::false_type {};
802using is_double_double = bool_constant<std::numeric_limits<T>::digits == 106>;
804#ifndef FMT_USE_FULL_CACHE_DRAGONBOX
805# define FMT_USE_FULL_CACHE_DRAGONBOX 0
808template <typename T, typename Enable = void>
809struct is_locale : std::false_type {};
811struct is_locale<T, void_t<decltype(T::classic())>> : std::true_type {};
818enum { inline_buffer_size = 500 };
833template <typename T, size_t SIZE = inline_buffer_size,
834 typename Allocator = std::allocator<T>>
835class basic_memory_buffer : public detail::buffer<T> {
840 FMT_NO_UNIQUE_ADDRESS Allocator alloc_;
843 FMT_CONSTEXPR20 void deallocate() {
844 T* data = this->
data();
845 if (data != store_) alloc_.deallocate(data, this->
capacity());
848 static FMT_CONSTEXPR20 void grow(detail::buffer<T>& buf, size_t size) {
849 detail::abort_fuzzing_if(
size > 5000);
850 auto& self =
static_cast<basic_memory_buffer&
>(buf);
851 const size_t max_size =
852 std::allocator_traits<Allocator>::max_size(self.alloc_);
853 size_t old_capacity = buf.capacity();
854 size_t new_capacity = old_capacity + old_capacity / 2;
855 if (
size > new_capacity)
857 else if (new_capacity > max_size)
858 new_capacity =
size > max_size ?
size : max_size;
859 T* old_data = buf.data();
860 T* new_data = self.alloc_.allocate(new_capacity);
862 detail::assume(buf.size() <= new_capacity);
864 memcpy(new_data, old_data, buf.size() *
sizeof(T));
865 self.set(new_data, new_capacity);
869 if (old_data != self.store_) self.alloc_.deallocate(old_data, old_capacity);
873 using value_type = T;
874 using const_reference =
const T&;
877 const Allocator& alloc = Allocator())
878 : detail::buffer<T>(grow), alloc_(alloc) {
879 this->set(store_, SIZE);
880 if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T());
882 FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); }
886 FMT_CONSTEXPR20
void move(basic_memory_buffer& other) {
887 alloc_ = std::move(other.alloc_);
888 T* data = other.
data();
889 size_t size = other.
size(), capacity = other.
capacity();
890 if (data == other.store_) {
891 this->set(store_, capacity);
892 detail::copy<T>(other.store_, other.store_ + size, store_);
894 this->set(data, capacity);
897 other.
set(other.store_, 0);
912 auto operator=(basic_memory_buffer&& other)
noexcept -> basic_memory_buffer& {
913 FMT_ASSERT(
this != &other,
"");
920 auto get_allocator() const -> Allocator {
return alloc_; }
924 FMT_CONSTEXPR20
void resize(
size_t count) { this->try_resize(count); }
927 void reserve(
size_t new_capacity) { this->try_reserve(new_capacity); }
930 template <
typename ContiguousRange>
931 void append(
const ContiguousRange& range) {
932 append(range.data(), range.data() + range.size());
938template <
typename T,
size_t SIZE,
typename Allocator>
944FMT_API
auto write_console(
int fd, string_view text) -> bool;
945FMT_API
void print(std::FILE*, string_view);
952# pragma clang diagnostic ignored "-Wweak-vtables"
956class FMT_SO_VISIBILITY(
"default") format_error :
public std::runtime_error {
958 using std::runtime_error::runtime_error;
962#if FMT_USE_NONTYPE_TEMPLATE_ARGS
963template <
typename Char,
size_t N>
struct fixed_string {
964 constexpr fixed_string(
const Char (&str)[N]) {
965 detail::copy<Char, const Char*, Char*>(
static_cast<const Char*
>(str),
973template <
typename Char,
size_t N>
974constexpr auto compile_string_to_view(
const Char (&s)[N])
978 return {s, N - (std::char_traits<Char>::to_int_type(s[N - 1]) == 0 ? 1 : 0)};
980template <
typename Char>
990template <
typename OutputIt,
typename Char>
class generic_context {
997 using char_type = Char;
998 using iterator = OutputIt;
1002 constexpr generic_context(OutputIt out,
1005 : out_(out), args_(ctx_args), loc_(loc) {}
1006 generic_context(generic_context&&) =
default;
1007 generic_context(
const generic_context&) =
delete;
1008 void operator=(
const generic_context&) =
delete;
1011 return args_.get(
id);
1014 return args_.get(name);
1017 return args_.get_id(name);
1023 FMT_CONSTEXPR
auto out() -> iterator {
return out_; }
1025 void advance_to(iterator it) {
1037 template <
typename T, FMT_ENABLE_IF(!detail::is_
float128<T>::value)>
1038 loc_value(T value) : value_(detail::make_arg<format_context>(value)) {}
1040 template <
typename T, FMT_ENABLE_IF(detail::is_
float128<T>::value)>
1043 template <
typename Visitor>
auto visit(Visitor&& vis) ->
decltype(vis(0)) {
1044 return value_.visit(vis);
1050template <
typename Locale>
class format_facet :
public Locale::facet {
1052 std::string separator_;
1053 std::string grouping_;
1054 std::string decimal_point_;
1057 virtual auto do_put(appender out,
loc_value val,
1061 static FMT_API
typename Locale::id id;
1063 explicit format_facet(Locale& loc);
1064 explicit format_facet(string_view sep =
"",
1065 std::initializer_list<unsigned char> g = {3},
1066 std::string decimal_point =
".")
1067 : separator_(sep.data(), sep.size()),
1068 grouping_(g.begin(), g.end()),
1069 decimal_point_(decimal_point) {}
1073 return do_put(out, val, specs);
1083template <
typename T, FMT_ENABLE_IF(is_
signed<T>::value)>
1084constexpr auto is_negative(T value) ->
bool {
1087template <
typename T, FMT_ENABLE_IF(!is_
signed<T>::value)>
1088constexpr auto is_negative(T) ->
bool {
1092template <
typename T>
1093FMT_CONSTEXPR
auto is_supported_floating_point(T) ->
bool {
1094 if (std::is_same<T, float>())
return FMT_USE_FLOAT;
1095 if (std::is_same<T, double>())
return FMT_USE_DOUBLE;
1096 if (std::is_same<T, long double>())
return FMT_USE_LONG_DOUBLE;
1102template <
typename T>
1103using uint32_or_64_or_128_t =
1104 conditional_t<num_bits<T>() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS,
1106 conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>;
1107template <
typename T>
1108using uint64_or_128_t = conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>;
1110#define FMT_POWERS_OF_10(factor) \
1111 factor * 10, (factor) * 100, (factor) * 1000, (factor) * 10000, \
1112 (factor) * 100000, (factor) * 1000000, (factor) * 10000000, \
1113 (factor) * 100000000, (factor) * 1000000000
1116constexpr auto digits2(
size_t value) ->
const char* {
1118 return &
"0001020304050607080910111213141516171819"
1119 "2021222324252627282930313233343536373839"
1120 "4041424344454647484950515253545556575859"
1121 "6061626364656667686970717273747576777879"
1122 "8081828384858687888990919293949596979899"[
value * 2];
1126template <
typename Char,
typename Sign>
constexpr auto sign(Sign s) -> Char {
1127#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604
1128 static_assert(std::is_same<Sign, sign_t>::value,
"");
1130 return static_cast<char>(((
' ' << 24) | (
'+' << 16) | (
'-' << 8)) >> (s * 8));
1133template <
typename T> FMT_CONSTEXPR
auto count_digits_fallback(T n) ->
int {
1139 if (n < 10)
return count;
1140 if (n < 100)
return count + 1;
1141 if (n < 1000)
return count + 2;
1142 if (n < 10000)
return count + 3;
1148FMT_CONSTEXPR
inline auto count_digits(uint128_opt n) ->
int {
1149 return count_digits_fallback(n);
1153#ifdef FMT_BUILTIN_CLZLL
1156inline auto do_count_digits(uint64_t n) ->
int {
1161 static constexpr uint8_t bsr2log10[] = {
1162 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
1163 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
1164 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
1165 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20};
1166 auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63];
1167 static constexpr const uint64_t zero_or_powers_of_10[] = {
1168 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL),
1169 10000000000000000000ULL};
1170 return t - (n < zero_or_powers_of_10[t]);
1176FMT_CONSTEXPR20
inline auto count_digits(uint64_t n) ->
int {
1177#ifdef FMT_BUILTIN_CLZLL
1178 if (!is_constant_evaluated())
return do_count_digits(n);
1180 return count_digits_fallback(n);
1184template <
int BITS,
typename UInt>
1185FMT_CONSTEXPR
auto count_digits(UInt n) ->
int {
1186#ifdef FMT_BUILTIN_CLZ
1187 if (!is_constant_evaluated() && num_bits<UInt>() == 32)
1188 return (FMT_BUILTIN_CLZ(
static_cast<uint32_t
>(n) | 1) ^ 31) / BITS + 1;
1195 }
while ((m >>= BITS) != 0);
1200#ifdef FMT_BUILTIN_CLZ
1203FMT_INLINE
auto do_count_digits(uint32_t n) ->
int {
1206# define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T)
1207 static constexpr uint64_t table[] = {
1208 FMT_INC(0), FMT_INC(0), FMT_INC(0),
1209 FMT_INC(10), FMT_INC(10), FMT_INC(10),
1210 FMT_INC(100), FMT_INC(100), FMT_INC(100),
1211 FMT_INC(1000), FMT_INC(1000), FMT_INC(1000),
1212 FMT_INC(10000), FMT_INC(10000), FMT_INC(10000),
1213 FMT_INC(100000), FMT_INC(100000), FMT_INC(100000),
1214 FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000),
1215 FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000),
1216 FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000),
1217 FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000),
1218 FMT_INC(1000000000), FMT_INC(1000000000)
1220 auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31];
1221 return static_cast<int>((n + inc) >> 32);
1226FMT_CONSTEXPR20
inline auto count_digits(uint32_t n) ->
int {
1227#ifdef FMT_BUILTIN_CLZ
1228 if (!is_constant_evaluated()) {
1229 return do_count_digits(n);
1232 return count_digits_fallback(n);
1235template <
typename Int>
constexpr auto digits10() noexcept ->
int {
1236 return std::numeric_limits<Int>::digits10;
1238template <>
constexpr auto digits10<int128_opt>() noexcept ->
int {
return 38; }
1239template <>
constexpr auto digits10<uint128_t>() noexcept ->
int {
return 38; }
1242 std::string grouping;
1246template <
typename Char>
1248template <
typename Char>
1250 auto result = thousands_sep_impl<char>(loc);
1251 return {result.grouping, Char(result.thousands_sep)};
1255 return thousands_sep_impl<wchar_t>(loc);
1258template <
typename Char>
1259FMT_API
auto decimal_point_impl(
locale_ref loc) -> Char;
1260template <
typename Char>
inline auto decimal_point(
locale_ref loc) -> Char {
1261 return Char(decimal_point_impl<char>(loc));
1263template <>
inline auto decimal_point(
locale_ref loc) ->
wchar_t {
1264 return decimal_point_impl<wchar_t>(loc);
1268template <
typename Char>
auto equal2(
const Char* lhs,
const char* rhs) ->
bool {
1269 return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]);
1271inline auto equal2(
const char* lhs,
const char* rhs) ->
bool {
1272 return memcmp(lhs, rhs, 2) == 0;
1276template <
typename Char>
1277FMT_CONSTEXPR20 FMT_INLINE
void copy2(Char* dst,
const char* src) {
1278 if (!is_constant_evaluated() &&
sizeof(Char) ==
sizeof(
char)) {
1279 memcpy(dst, src, 2);
1282 *dst++ =
static_cast<Char
>(*src++);
1283 *dst =
static_cast<Char
>(*src);
1294template <
typename Char,
typename UInt>
1295FMT_CONSTEXPR20
auto format_decimal(Char* out, UInt
value,
int size)
1297 FMT_ASSERT(size >= count_digits(
value),
"invalid digit count");
1300 while (
value >= 100) {
1305 copy2(out, digits2(
static_cast<size_t>(
value % 100)));
1309 *--out =
static_cast<Char
>(
'0' + value);
1313 copy2(out, digits2(
static_cast<size_t>(
value)));
1317template <
typename Char,
typename UInt,
typename Iterator,
1318 FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<Iterator>>::value)>
1319FMT_CONSTEXPR
inline auto format_decimal(Iterator out, UInt
value,
int size)
1322 Char
buffer[digits10<UInt>() + 1] = {};
1323 auto end = format_decimal(
buffer,
value, size).end;
1324 return {out, detail::copy_noinline<Char>(
buffer, end, out)};
1327template <
unsigned BASE_BITS,
typename Char,
typename UInt>
1328FMT_CONSTEXPR
auto format_uint(Char*
buffer, UInt
value,
int num_digits,
1329 bool upper =
false) -> Char* {
1333 const char* digits = upper ?
"0123456789ABCDEF" :
"0123456789abcdef";
1334 unsigned digit =
static_cast<unsigned>(
value & ((1 << BASE_BITS) - 1));
1335 *--
buffer =
static_cast<Char
>(BASE_BITS < 4 ? static_cast<char>(
'0' + digit)
1337 }
while ((
value >>= BASE_BITS) != 0);
1341template <
unsigned BASE_BITS,
typename Char,
typename It,
typename UInt>
1342FMT_CONSTEXPR
inline auto format_uint(It out, UInt
value,
int num_digits,
1343 bool upper =
false) -> It {
1344 if (
auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
1345 format_uint<BASE_BITS>(ptr,
value, num_digits, upper);
1349 char buffer[num_bits<UInt>() / BASE_BITS + 1] = {};
1350 format_uint<BASE_BITS>(
buffer,
value, num_digits, upper);
1351 return detail::copy_noinline<Char>(
buffer,
buffer + num_digits, out);
1355class utf8_to_utf16 {
1360 FMT_API
explicit utf8_to_utf16(string_view s);
1362 auto size()
const ->
size_t {
return buffer_.size() - 1; }
1363 auto c_str()
const ->
const wchar_t* {
return &buffer_[0]; }
1364 auto str()
const -> std::wstring {
return {&buffer_[0], size()}; }
1367enum class to_utf8_error_policy { abort, replace };
1370template <
typename WChar,
typename Buffer = memory_buffer>
class to_utf8 {
1377 to_utf8_error_policy policy = to_utf8_error_policy::abort) {
1378 static_assert(
sizeof(WChar) == 2 ||
sizeof(WChar) == 4,
1379 "Expect utf16 or utf32");
1380 if (!convert(s, policy))
1381 FMT_THROW(std::runtime_error(
sizeof(WChar) == 2 ?
"invalid utf16"
1382 :
"invalid utf32"));
1384 operator string_view()
const {
return string_view(&buffer_[0], size()); }
1385 auto size()
const ->
size_t {
return buffer_.size() - 1; }
1386 auto c_str()
const ->
const char* {
return &buffer_[0]; }
1387 auto str()
const -> std::string {
return std::string(&buffer_[0], size()); }
1393 to_utf8_error_policy policy = to_utf8_error_policy::abort)
1395 if (!convert(buffer_, s, policy))
return false;
1396 buffer_.push_back(0);
1400 to_utf8_error_policy policy = to_utf8_error_policy::abort)
1402 for (
auto p = s.begin(); p != s.end(); ++p) {
1403 uint32_t c =
static_cast<uint32_t
>(*p);
1404 if (
sizeof(WChar) == 2 && c >= 0xd800 && c <= 0xdfff) {
1407 if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) {
1408 if (policy == to_utf8_error_policy::abort)
return false;
1409 buf.append(string_view(
"\xEF\xBF\xBD"));
1412 c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;
1414 }
else if (c < 0x80) {
1415 buf.push_back(
static_cast<char>(c));
1416 }
else if (c < 0x800) {
1417 buf.push_back(
static_cast<char>(0xc0 | (c >> 6)));
1418 buf.push_back(
static_cast<char>(0x80 | (c & 0x3f)));
1419 }
else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
1420 buf.push_back(
static_cast<char>(0xe0 | (c >> 12)));
1421 buf.push_back(
static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
1422 buf.push_back(
static_cast<char>(0x80 | (c & 0x3f)));
1423 }
else if (c >= 0x10000 && c <= 0x10ffff) {
1424 buf.push_back(
static_cast<char>(0xf0 | (c >> 18)));
1425 buf.push_back(
static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
1426 buf.push_back(
static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
1427 buf.push_back(
static_cast<char>(0x80 | (c & 0x3f)));
1439 auto p =
static_cast<uint128_opt
>(x) *
static_cast<uint128_opt
>(y);
1440 return {
static_cast<uint64_t
>(p >> 64),
static_cast<uint64_t
>(p)};
1441#elif defined(_MSC_VER) && defined(_M_X64)
1442 auto hi = uint64_t();
1443 auto lo = _umul128(x, y, &hi);
1446 const uint64_t mask =
static_cast<uint64_t
>(max_value<uint32_t>());
1448 uint64_t a = x >> 32;
1449 uint64_t b = x & mask;
1450 uint64_t c = y >> 32;
1451 uint64_t d = y & mask;
1453 uint64_t ac = a * c;
1454 uint64_t bc = b * c;
1455 uint64_t ad = a * d;
1456 uint64_t bd = b * d;
1458 uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask);
1460 return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32),
1461 (intermediate << 32) + (bd & mask)};
1465namespace dragonbox {
1468inline auto floor_log10_pow2(
int e)
noexcept ->
int {
1469 FMT_ASSERT(e <= 2620 && e >= -2620,
"too large exponent");
1470 static_assert((-1 >> 1) == -1,
"right shift is not arithmetic");
1471 return (e * 315653) >> 20;
1474inline auto floor_log2_pow10(
int e)
noexcept ->
int {
1475 FMT_ASSERT(e <= 1233 && e >= -1233,
"too large exponent");
1476 return (e * 1741647) >> 19;
1480inline auto umul128_upper64(uint64_t x, uint64_t y)
noexcept -> uint64_t {
1482 auto p =
static_cast<uint128_opt
>(x) *
static_cast<uint128_opt
>(y);
1483 return static_cast<uint64_t
>(p >> 64);
1484#elif defined(_MSC_VER) && defined(_M_X64)
1485 return __umulh(x, y);
1487 return umul128(x, y).high();
1493inline auto umul192_upper128(uint64_t x, uint128_fallback y)
noexcept
1494 -> uint128_fallback {
1495 uint128_fallback r = umul128(x, y.high());
1496 r += umul128_upper64(x, y.low());
1500FMT_API
auto get_cached_power(
int k)
noexcept -> uint128_fallback;
1506 using carrier_uint = uint32_t;
1507 static const int exponent_bits = 8;
1508 static const int kappa = 1;
1509 static const int big_divisor = 100;
1510 static const int small_divisor = 10;
1511 static const int min_k = -31;
1512 static const int max_k = 46;
1513 static const int shorter_interval_tie_lower_threshold = -35;
1514 static const int shorter_interval_tie_upper_threshold = -35;
1518 using carrier_uint = uint64_t;
1519 static const int exponent_bits = 11;
1520 static const int kappa = 2;
1521 static const int big_divisor = 1000;
1522 static const int small_divisor = 100;
1523 static const int min_k = -292;
1524 static const int max_k = 341;
1525 static const int shorter_interval_tie_lower_threshold = -77;
1526 static const int shorter_interval_tie_upper_threshold = -77;
1530template <
typename T>
1531struct float_info<T, enable_if_t<std::numeric_limits<T>::digits == 64 ||
1532 std::numeric_limits<T>::digits == 113 ||
1534 using carrier_uint = detail::uint128_t;
1535 static const int exponent_bits = 15;
1539template <
typename T>
1541 using carrier_uint = detail::uint128_t;
1546 significand_type significand;
1550template <
typename T> FMT_API
auto to_decimal(T x)
noexcept ->
decimal_fp<T>;
1554template <
typename Float>
constexpr auto has_implicit_bit() ->
bool {
1556 return std::numeric_limits<Float>::digits != 64;
1561template <
typename Float>
constexpr auto num_significand_bits() ->
int {
1563 return is_float128<Float>() ? 112
1564 : (std::numeric_limits<Float>::digits -
1565 (has_implicit_bit<Float>() ? 1 : 0));
1568template <
typename Float>
1569constexpr auto exponent_mask() ->
1573 << num_significand_bits<Float>();
1575template <
typename Float>
constexpr auto exponent_bias() ->
int {
1577 return is_float128<Float>() ? 16383
1578 : std::numeric_limits<Float>::max_exponent - 1;
1582template <
typename Char,
typename It>
1583FMT_CONSTEXPR
auto write_exponent(
int exp, It it) -> It {
1584 FMT_ASSERT(-10000 < exp && exp < 10000,
"exponent out of range");
1586 *it++ =
static_cast<Char
>(
'-');
1589 *it++ =
static_cast<Char
>(
'+');
1592 const char* top = digits2(to_unsigned(exp / 100));
1593 if (exp >= 1000) *it++ =
static_cast<Char
>(top[0]);
1594 *it++ =
static_cast<Char
>(top[1]);
1597 const char* d = digits2(to_unsigned(exp));
1598 *it++ =
static_cast<Char
>(d[0]);
1599 *it++ =
static_cast<Char
>(d[1]);
1604template <
typename F>
struct basic_fp {
1608 static constexpr const int num_significand_bits =
1609 static_cast<int>(
sizeof(F) * num_bits<unsigned char>());
1611 constexpr basic_fp() : f(0), e(0) {}
1612 constexpr basic_fp(uint64_t f_val,
int e_val) : f(f_val), e(e_val) {}
1615 template <
typename Float> FMT_CONSTEXPR basic_fp(Float n) { assign(n); }
1618 template <
typename Float, FMT_ENABLE_IF(!is_
double_
double<Float>::value)>
1619 FMT_CONSTEXPR
auto assign(Float n) ->
bool {
1620 static_assert(std::numeric_limits<Float>::digits <= 113,
"unsupported FP");
1623 const auto num_float_significand_bits =
1624 detail::num_significand_bits<Float>();
1625 const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
1626 const auto significand_mask = implicit_bit - 1;
1627 auto u = bit_cast<carrier_uint>(n);
1628 f =
static_cast<F
>(u & significand_mask);
1629 auto biased_e =
static_cast<int>((u & exponent_mask<Float>()) >>
1630 num_float_significand_bits);
1633 auto is_predecessor_closer = f == 0 && biased_e > 1;
1636 else if (has_implicit_bit<Float>())
1637 f +=
static_cast<F
>(implicit_bit);
1638 e = biased_e - exponent_bias<Float>() - num_float_significand_bits;
1639 if (!has_implicit_bit<Float>()) ++e;
1640 return is_predecessor_closer;
1643 template <
typename Float, FMT_ENABLE_IF(is_
double_
double<Float>::value)>
1644 FMT_CONSTEXPR
auto assign(Float n) ->
bool {
1645 static_assert(std::numeric_limits<double>::is_iec559,
"unsupported FP");
1646 return assign(
static_cast<double>(n));
1653template <
int SHIFT = 0,
typename F>
1656 const auto implicit_bit = F(1) << num_significand_bits<double>();
1657 const auto shifted_implicit_bit = implicit_bit << SHIFT;
1658 while ((
value.f & shifted_implicit_bit) == 0) {
1663 const auto offset = basic_fp<F>::num_significand_bits -
1664 num_significand_bits<double>() - SHIFT - 1;
1671FMT_CONSTEXPR
inline auto multiply(uint64_t lhs, uint64_t rhs) -> uint64_t {
1673 auto product =
static_cast<__uint128_t
>(lhs) * rhs;
1674 auto f =
static_cast<uint64_t
>(product >> 64);
1675 return (
static_cast<uint64_t
>(product) & (1ULL << 63)) != 0 ? f + 1 : f;
1678 uint64_t mask = (1ULL << 32) - 1;
1679 uint64_t a = lhs >> 32, b = lhs & mask;
1680 uint64_t c = rhs >> 32, d = rhs & mask;
1681 uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
1683 uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
1684 return ac + (ad >> 32) + (bc >> 32) + (mid >> 32);
1688FMT_CONSTEXPR
inline auto operator*(fp x, fp y) -> fp {
1689 return {multiply(x.f, y.f), x.e + y.e + 64};
1692template <typename T, bool doublish = num_bits<T>() == num_bits<double>()>
1693using convert_float_result =
1694 conditional_t<std::is_same<T, float>::value || doublish, double, T>;
1696template <
typename T>
1697constexpr auto convert_float(T
value) -> convert_float_result<T> {
1698 return static_cast<convert_float_result<T>
>(
value);
1701template <
typename Char,
typename OutputIt>
1702FMT_NOINLINE FMT_CONSTEXPR
auto fill(OutputIt it,
size_t n,
const fill_t& fill)
1704 auto fill_size = fill.size();
1705 if (fill_size == 1)
return detail::fill_n(it, n, fill.template get<Char>());
1706 if (
const Char* data = fill.template data<Char>()) {
1707 for (
size_t i = 0; i < n; ++i) it = copy<Char>(data, data + fill_size, it);
1715template <
typename Char, align::type align = align::left,
typename OutputIt,
1717FMT_CONSTEXPR
auto write_padded(OutputIt out,
const format_specs& specs,
1718 size_t size,
size_t width, F&& f) -> OutputIt {
1719 static_assert(align == align::left || align == align::right,
"");
1720 unsigned spec_width = to_unsigned(specs.width);
1721 size_t padding = spec_width > width ? spec_width - width : 0;
1724 auto* shifts = align == align::left ?
"\x1f\x1f\x00\x01" :
"\x00\x1f\x00\x01";
1725 size_t left_padding = padding >> shifts[specs.align];
1726 size_t right_padding = padding - left_padding;
1727 auto it = reserve(out, size + padding * specs.fill.size());
1728 if (left_padding != 0) it = fill<Char>(it, left_padding, specs.fill);
1730 if (right_padding != 0) it = fill<Char>(it, right_padding, specs.fill);
1731 return base_iterator(out, it);
1734template <
typename Char, align::type align = align::left,
typename OutputIt,
1736constexpr auto write_padded(OutputIt out,
const format_specs& specs,
1737 size_t size, F&& f) -> OutputIt {
1738 return write_padded<Char, align>(out, specs, size, size, f);
1741template <
typename Char, align::type align = align::left,
typename OutputIt>
1742FMT_CONSTEXPR
auto write_bytes(OutputIt out, string_view bytes,
1743 const format_specs& specs = {}) -> OutputIt {
1744 return write_padded<Char, align>(
1745 out, specs, bytes.
size(), [bytes](reserve_iterator<OutputIt> it) {
1746 const char* data = bytes.data();
1747 return copy<Char>(data, data + bytes.size(), it);
1751template <
typename Char,
typename OutputIt,
typename UIntPtr>
1752auto write_ptr(OutputIt out, UIntPtr
value,
const format_specs* specs)
1754 int num_digits = count_digits<4>(
value);
1755 auto size = to_unsigned(num_digits) + size_t(2);
1756 auto write = [=](reserve_iterator<OutputIt> it) {
1757 *it++ =
static_cast<Char
>(
'0');
1758 *it++ =
static_cast<Char
>(
'x');
1759 return format_uint<4, Char>(it,
value, num_digits);
1761 return specs ? write_padded<Char, align::right>(out, *specs, size, write)
1762 : base_iterator(out, write(reserve(out, size)));
1766FMT_API
auto is_printable(uint32_t cp) -> bool;
1768inline auto needs_escape(uint32_t cp) ->
bool {
1769 return cp < 0x20 || cp == 0x7f || cp ==
'"' || cp ==
'\\' ||
1779template <
typename Char>
1780auto find_escape(
const Char* begin,
const Char* end)
1782 for (; begin != end; ++begin) {
1783 uint32_t cp =
static_cast<unsigned_char<Char>
>(*begin);
1784 if (const_check(
sizeof(Char) == 1) && cp >= 0x80)
continue;
1785 if (needs_escape(cp))
return {begin, begin + 1, cp};
1787 return {begin,
nullptr, 0};
1790inline auto find_escape(
const char* begin,
const char* end)
1792 if (!use_utf8())
return find_escape<char>(begin, end);
1794 for_each_codepoint(string_view(begin, to_unsigned(end - begin)),
1795 [&](uint32_t cp, string_view sv) {
1796 if (needs_escape(cp)) {
1797 result = {sv.begin(), sv.end(), cp};
1805#define FMT_STRING_IMPL(s, base, explicit) \
1809 struct FMT_VISIBILITY("hidden") FMT_COMPILE_STRING : base { \
1810 using char_type FMT_MAYBE_UNUSED = fmt::remove_cvref_t<decltype(s[0])>; \
1811 FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \
1812 operator fmt::basic_string_view<char_type>() const { \
1813 return fmt::detail_exported::compile_string_to_view<char_type>(s); \
1816 return FMT_COMPILE_STRING(); \
1827#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string, )
1829template <
size_t w
idth,
typename Char,
typename OutputIt>
1830auto write_codepoint(OutputIt out,
char prefix, uint32_t cp) -> OutputIt {
1831 *out++ =
static_cast<Char
>(
'\\');
1832 *out++ =
static_cast<Char
>(prefix);
1834 fill_n(buf, width,
static_cast<Char
>(
'0'));
1835 format_uint<4>(buf, cp, width);
1836 return copy<Char>(buf, buf + width, out);
1839template <
typename OutputIt,
typename Char>
1842 auto c =
static_cast<Char
>(escape.cp);
1843 switch (escape.cp) {
1845 *out++ =
static_cast<Char
>(
'\\');
1846 c =
static_cast<Char
>(
'n');
1849 *out++ =
static_cast<Char
>(
'\\');
1850 c =
static_cast<Char
>(
'r');
1853 *out++ =
static_cast<Char
>(
'\\');
1854 c =
static_cast<Char
>(
't');
1861 *out++ =
static_cast<Char
>(
'\\');
1864 if (escape.cp < 0x100)
return write_codepoint<2, Char>(out,
'x', escape.cp);
1865 if (escape.cp < 0x10000)
1866 return write_codepoint<4, Char>(out,
'u', escape.cp);
1867 if (escape.cp < 0x110000)
1868 return write_codepoint<8, Char>(out,
'U', escape.cp);
1869 for (Char escape_char : basic_string_view<Char>(
1870 escape.begin, to_unsigned(escape.end - escape.begin))) {
1871 out = write_codepoint<2, Char>(out,
'x',
1872 static_cast<uint32_t
>(escape_char) & 0xFF);
1880template <
typename Char,
typename OutputIt>
1881auto write_escaped_string(OutputIt out, basic_string_view<Char> str)
1883 *out++ =
static_cast<Char
>(
'"');
1884 auto begin = str.begin(), end = str.end();
1886 auto escape = find_escape(begin, end);
1887 out = copy<Char>(begin, escape.begin, out);
1890 out = write_escaped_cp<OutputIt, Char>(out, escape);
1891 }
while (begin != end);
1892 *out++ =
static_cast<Char
>(
'"');
1896template <
typename Char,
typename OutputIt>
1897auto write_escaped_char(OutputIt out, Char v) -> OutputIt {
1898 Char v_array[1] = {v};
1899 *out++ =
static_cast<Char
>(
'\'');
1900 if ((needs_escape(
static_cast<uint32_t
>(v)) && v !=
static_cast<Char
>(
'"')) ||
1901 v ==
static_cast<Char
>(
'\'')) {
1902 out = write_escaped_cp(out,
1904 static_cast<uint32_t
>(v)});
1908 *out++ =
static_cast<Char
>(
'\'');
1912template <
typename Char,
typename OutputIt>
1913FMT_CONSTEXPR
auto write_char(OutputIt out, Char
value,
1914 const format_specs& specs) -> OutputIt {
1915 bool is_debug = specs.type == presentation_type::debug;
1916 return write_padded<Char>(out, specs, 1, [=](reserve_iterator<OutputIt> it) {
1917 if (is_debug)
return write_escaped_char(it,
value);
1922template <
typename Char,
typename OutputIt>
1923FMT_CONSTEXPR
auto write(OutputIt out, Char
value,
const format_specs& specs,
1926 using unsigned_type =
1927 conditional_t<std::is_same<Char, char>::value,
unsigned char,
unsigned>;
1928 return check_char_specs(specs)
1929 ? write_char<Char>(out,
value, specs)
1930 : write<Char>(out, static_cast<unsigned_type>(
value), specs, loc);
1935template <
typename Char>
struct write_int_data {
1939 FMT_CONSTEXPR write_int_data(
int num_digits,
unsigned prefix,
1941 : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) {
1942 if (specs.align == align::numeric) {
1943 auto width = to_unsigned(specs.width);
1945 padding = width - size;
1948 }
else if (specs.precision > num_digits) {
1949 size = (prefix >> 24) + to_unsigned(specs.precision);
1950 padding = to_unsigned(specs.precision - num_digits);
1959template <
typename Char,
typename OutputIt,
typename W>
1960FMT_CONSTEXPR FMT_INLINE
auto write_int(OutputIt out,
int num_digits,
1963 W write_digits) -> OutputIt {
1965 if ((specs.width | (specs.precision + 1)) == 0) {
1966 auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24));
1968 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
1969 *it++ =
static_cast<Char
>(p & 0xff);
1971 return base_iterator(out, write_digits(it));
1974 return write_padded<Char, align::right>(
1975 out, specs, data.size, [=](reserve_iterator<OutputIt> it) {
1976 for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
1977 *it++ = static_cast<Char>(p & 0xff);
1978 it = detail::fill_n(it, data.padding, static_cast<Char>(
'0'));
1979 return write_digits(it);
1983template <
typename Char>
class digit_grouping {
1985 std::string grouping_;
1986 std::basic_string<Char> thousands_sep_;
1989 std::string::const_iterator group;
1992 auto initial_state()
const -> next_state {
return {grouping_.begin(), 0}; }
1995 auto next(next_state& state)
const ->
int {
1996 if (thousands_sep_.empty())
return max_value<int>();
1997 if (state.group == grouping_.end())
return state.pos += grouping_.back();
1998 if (*state.group <= 0 || *state.group == max_value<char>())
1999 return max_value<int>();
2000 state.pos += *state.group++;
2005 explicit digit_grouping(
locale_ref loc,
bool localized =
true) {
2006 if (!localized)
return;
2007 auto sep = thousands_sep<Char>(loc);
2008 grouping_ = sep.grouping;
2009 if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep);
2011 digit_grouping(std::string grouping, std::basic_string<Char> sep)
2012 : grouping_(std::move(grouping)), thousands_sep_(std::move(sep)) {}
2014 auto has_separator()
const ->
bool {
return !thousands_sep_.empty(); }
2016 auto count_separators(
int num_digits)
const ->
int {
2018 auto state = initial_state();
2019 while (num_digits > next(state)) ++count;
2024 template <
typename Out,
typename C>
2026 auto num_digits =
static_cast<int>(digits.
size());
2028 separators.push_back(0);
2029 auto state = initial_state();
2030 while (
int i = next(state)) {
2031 if (i >= num_digits)
break;
2032 separators.push_back(i);
2034 for (
int i = 0, sep_index =
static_cast<int>(separators.size() - 1);
2035 i < num_digits; ++i) {
2036 if (num_digits - i == separators[sep_index]) {
2037 out = copy<Char>(thousands_sep_.data(),
2038 thousands_sep_.data() + thousands_sep_.size(), out);
2041 *out++ =
static_cast<Char
>(digits[to_unsigned(i)]);
2047FMT_CONSTEXPR
inline void prefix_append(
unsigned& prefix,
unsigned value) {
2049 prefix += (1u + (
value > 0xff ? 1 : 0)) << 24;
2053template <
typename OutputIt,
typename UInt,
typename Char>
2054auto write_int(OutputIt out, UInt value,
unsigned prefix,
2055 const format_specs& specs,
const digit_grouping<Char>& grouping)
2057 static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value,
"");
2059 auto buffer = memory_buffer();
2060 switch (specs.type) {
2062 FMT_ASSERT(
false,
"");
2064 case presentation_type::none:
2065 case presentation_type::dec:
2066 num_digits = count_digits(value);
2067 format_decimal<char>(appender(buffer), value, num_digits);
2069 case presentation_type::hex:
2071 prefix_append(prefix,
unsigned(specs.upper ?
'X' :
'x') << 8 |
'0');
2072 num_digits = count_digits<4>(value);
2073 format_uint<4, char>(appender(buffer), value, num_digits, specs.upper);
2075 case presentation_type::oct:
2076 num_digits = count_digits<3>(value);
2079 if (specs.alt && specs.precision <= num_digits && value != 0)
2080 prefix_append(prefix,
'0');
2081 format_uint<3, char>(appender(buffer), value, num_digits);
2083 case presentation_type::bin:
2085 prefix_append(prefix,
unsigned(specs.upper ?
'B' :
'b') << 8 |
'0');
2086 num_digits = count_digits<1>(value);
2087 format_uint<1, char>(appender(buffer), value, num_digits);
2089 case presentation_type::chr:
2090 return write_char<Char>(out,
static_cast<Char
>(value), specs);
2093 unsigned size = (prefix != 0 ? prefix >> 24 : 0) + to_unsigned(num_digits) +
2094 to_unsigned(grouping.count_separators(num_digits));
2095 return write_padded<Char, align::right>(
2096 out, specs, size, size, [&](reserve_iterator<OutputIt> it) {
2097 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
2098 *it++ =
static_cast<Char
>(p & 0xff);
2104FMT_API
auto write_loc(appender out, loc_value
value,
const format_specs& specs,
2106template <
typename OutputIt>
2107inline auto write_loc(OutputIt, loc_value,
const format_specs&,
locale_ref)
2117template <
typename T>
2118FMT_CONSTEXPR
auto make_write_int_arg(T
value, sign_t sign)
2121 auto abs_value =
static_cast<uint32_or_64_or_128_t<T>
>(
value);
2122 if (is_negative(
value)) {
2123 prefix = 0x01000000 |
'-';
2124 abs_value = 0 - abs_value;
2126 constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u |
'+',
2128 prefix = prefixes[sign];
2130 return {abs_value, prefix};
2136 std::basic_string<Char> sep;
2137 std::string grouping;
2138 std::basic_string<Char> decimal_point;
2140 template <
typename T, FMT_ENABLE_IF(is_
integer<T>::value)>
2141 auto operator()(T
value) ->
bool {
2142 auto arg = make_write_int_arg(
value, specs.sign);
2143 write_int(out,
static_cast<uint64_or_128_t<T>
>(arg.abs_value), arg.prefix,
2148 template <
typename T, FMT_ENABLE_IF(!is_
integer<T>::value)>
2149 auto operator()(T) ->
bool {
2154template <
typename Char,
typename OutputIt,
typename T>
2158 static_assert(std::is_same<T, uint32_or_64_or_128_t<T>>
::value,
"");
2159 auto abs_value = arg.abs_value;
2160 auto prefix = arg.prefix;
2161 switch (specs.type) {
2163 FMT_ASSERT(
false,
"");
2165 case presentation_type::none:
2166 case presentation_type::dec: {
2167 int num_digits = count_digits(abs_value);
2168 return write_int<Char>(
2169 out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
2170 return format_decimal<Char>(it, abs_value, num_digits).end;
2173 case presentation_type::hex: {
2175 prefix_append(prefix,
unsigned(specs.upper ?
'X' :
'x') << 8 |
'0');
2176 int num_digits = count_digits<4>(abs_value);
2177 return write_int<Char>(
2178 out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
2179 return format_uint<4, Char>(it, abs_value, num_digits, specs.upper);
2182 case presentation_type::oct: {
2183 int num_digits = count_digits<3>(abs_value);
2186 if (specs.alt && specs.precision <= num_digits && abs_value != 0)
2187 prefix_append(prefix,
'0');
2188 return write_int<Char>(
2189 out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
2190 return format_uint<3, Char>(it, abs_value, num_digits);
2193 case presentation_type::bin: {
2195 prefix_append(prefix,
unsigned(specs.upper ?
'B' :
'b') << 8 |
'0');
2196 int num_digits = count_digits<1>(abs_value);
2197 return write_int<Char>(
2198 out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
2199 return format_uint<1, Char>(it, abs_value, num_digits);
2202 case presentation_type::chr:
2203 return write_char<Char>(out,
static_cast<Char
>(abs_value), specs);
2206template <
typename Char,
typename OutputIt,
typename T>
2207FMT_CONSTEXPR FMT_NOINLINE
auto write_int_noinline(OutputIt out,
2209 const format_specs& specs,
2211 return write_int<Char>(out, arg, specs, loc);
2213template <
typename Char,
typename T,
2215 !std::is_same<T, bool>::value &&
2216 !std::is_same<T, Char>::value)>
2217FMT_CONSTEXPR FMT_INLINE
auto write(basic_appender<Char> out, T
value,
2219 -> basic_appender<Char> {
2220 if (specs.localized && write_loc(out,
value, specs, loc))
return out;
2221 return write_int_noinline<Char>(out, make_write_int_arg(
value, specs.sign),
2225template <
typename Char,
typename OutputIt,
typename T,
2227 !std::is_same<T, bool>::value &&
2228 !std::is_same<T, Char>::value &&
2229 !std::is_same<OutputIt, basic_appender<Char>>::value)>
2230FMT_CONSTEXPR FMT_INLINE
auto write(OutputIt out, T
value,
2233 if (specs.localized && write_loc(out,
value, specs, loc))
return out;
2234 return write_int<Char>(out, make_write_int_arg(
value, specs.sign), specs,
2240class counting_iterator {
2245 using iterator_category = std::output_iterator_tag;
2246 using difference_type = std::ptrdiff_t;
2247 using pointer = void;
2248 using reference = void;
2249 FMT_UNCHECKED_ITERATOR(counting_iterator);
2252 template <
typename T> FMT_CONSTEXPR
void operator=(
const T&) {}
2255 FMT_CONSTEXPR counting_iterator() : count_(0) {}
2257 FMT_CONSTEXPR
auto count() const ->
size_t {
return count_; }
2259 FMT_CONSTEXPR
auto operator++() -> counting_iterator& {
2263 FMT_CONSTEXPR
auto operator++(
int) -> counting_iterator {
2269 FMT_CONSTEXPR
friend auto operator+(counting_iterator it, difference_type n)
2270 -> counting_iterator {
2271 it.count_ +=
static_cast<size_t>(n);
2275 FMT_CONSTEXPR
auto operator*() const ->
value_type {
return {}; }
2278template <
typename Char,
typename OutputIt>
2279FMT_CONSTEXPR
auto write(OutputIt out, basic_string_view<Char> s,
2280 const format_specs& specs) -> OutputIt {
2281 auto data = s.
data();
2282 auto size = s.
size();
2283 if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
2284 size = code_point_index(s, to_unsigned(specs.precision));
2285 bool is_debug = specs.type == presentation_type::debug;
2290 if (specs.width != 0) {
2294 width = compute_width(basic_string_view<Char>(data, size));
2296 return write_padded<Char>(out, specs, size, width,
2297 [=](reserve_iterator<OutputIt> it) {
2298 if (is_debug)
return write_escaped_string(it, s);
2299 return copy<Char>(data, data + size, it);
2302template <
typename Char,
typename OutputIt>
2303FMT_CONSTEXPR
auto write(OutputIt out,
2304 basic_string_view<type_identity_t<Char>> s,
2305 const format_specs& specs,
locale_ref) -> OutputIt {
2306 return write<Char>(out, s, specs);
2308template <
typename Char,
typename OutputIt>
2309FMT_CONSTEXPR
auto write(OutputIt out,
const Char* s,
const format_specs& specs,
2311 if (specs.type == presentation_type::pointer)
2312 return write_ptr<Char>(out, bit_cast<uintptr_t>(s), &specs);
2313 if (!s) report_error(
"string pointer is null");
2314 return write<Char>(out, basic_string_view<Char>(s), specs, {});
2317template <
typename Char,
typename OutputIt,
typename T,
2319 !std::is_same<T, bool>::value &&
2320 !std::is_same<T, Char>::value)>
2321FMT_CONSTEXPR
auto write(OutputIt out, T
value) -> OutputIt {
2322 auto abs_value =
static_cast<uint32_or_64_or_128_t<T>
>(
value);
2323 bool negative = is_negative(
value);
2325 if (negative) abs_value = ~abs_value + 1;
2326 int num_digits = count_digits(abs_value);
2327 auto size = (negative ? 1 : 0) +
static_cast<size_t>(num_digits);
2328 if (
auto ptr = to_pointer<Char>(out, size)) {
2329 if (negative) *ptr++ =
static_cast<Char
>(
'-');
2330 format_decimal<Char>(ptr, abs_value, num_digits);
2333 if (negative) *out++ =
static_cast<Char
>(
'-');
2334 return format_decimal<Char>(out, abs_value, num_digits).end;
2338template <
typename Char>
2339FMT_CONSTEXPR
auto parse_align(
const Char* begin,
const Char* end,
2340 format_specs& specs) ->
const Char* {
2341 FMT_ASSERT(begin != end,
"");
2342 auto align = align::none;
2343 auto p = begin + code_point_length(begin);
2344 if (end - p <= 0) p = begin;
2346 switch (to_ascii(*p)) {
2348 align = align::left;
2351 align = align::right;
2354 align = align::center;
2357 if (align != align::none) {
2360 if (c ==
'}')
return begin;
2362 report_error(
"invalid fill character '{'");
2365 specs.fill = basic_string_view<Char>(begin, to_unsigned(p - begin));
2371 }
else if (p == begin) {
2376 specs.align = align;
2381enum class float_format :
unsigned char {
2389 float_format format : 8;
2397FMT_CONSTEXPR
inline auto parse_float_type_spec(
const format_specs& specs)
2400 result.showpoint = specs.alt;
2401 result.locale = specs.localized;
2402 switch (specs.type) {
2405 case presentation_type::none:
2406 result.format = float_format::general;
2408 case presentation_type::exp:
2409 result.format = float_format::exp;
2410 result.showpoint |= specs.precision != 0;
2412 case presentation_type::fixed:
2413 result.format = float_format::fixed;
2414 result.showpoint |= specs.precision != 0;
2416 case presentation_type::general:
2417 result.format = float_format::general;
2423template <
typename Char,
typename OutputIt>
2424FMT_CONSTEXPR20
auto write_nonfinite(OutputIt out,
bool isnan,
2425 format_specs specs, sign_t sign)
2428 isnan ? (specs.upper ?
"NAN" :
"nan") : (specs.upper ?
"INF" :
"inf");
2429 constexpr size_t str_size = 3;
2430 auto size = str_size + (sign ? 1 : 0);
2432 const bool is_zero_fill =
2433 specs.fill.size() == 1 && specs.fill.template get<Char>() ==
'0';
2434 if (is_zero_fill) specs.fill =
' ';
2435 return write_padded<Char>(out, specs, size,
2436 [=](reserve_iterator<OutputIt> it) {
2437 if (sign) *it++ = detail::sign<Char>(sign);
2438 return copy<Char>(str, str + str_size, it);
2444 const char* significand;
2445 int significand_size;
2449constexpr auto get_significand_size(
const big_decimal_fp& f) ->
int {
2450 return f.significand_size;
2452template <
typename T>
2453inline auto get_significand_size(
const dragonbox::decimal_fp<T>& f) ->
int {
2454 return count_digits(f.significand);
2457template <
typename Char,
typename OutputIt>
2458constexpr auto write_significand(OutputIt out,
const char* significand,
2459 int significand_size) -> OutputIt {
2460 return copy<Char>(significand, significand + significand_size, out);
2462template <
typename Char,
typename OutputIt,
typename UInt>
2463inline auto write_significand(OutputIt out, UInt significand,
2464 int significand_size) -> OutputIt {
2465 return format_decimal<Char>(out, significand, significand_size).end;
2467template <
typename Char,
typename OutputIt,
typename T,
typename Grouping>
2468FMT_CONSTEXPR20
auto write_significand(OutputIt out, T significand,
2469 int significand_size,
int exponent,
2470 const Grouping& grouping) -> OutputIt {
2471 if (!grouping.has_separator()) {
2472 out = write_significand<Char>(out, significand, significand_size);
2473 return detail::fill_n(out, exponent,
static_cast<Char
>(
'0'));
2475 auto buffer = memory_buffer();
2476 write_significand<char>(appender(
buffer), significand, significand_size);
2477 detail::fill_n(appender(
buffer), exponent,
'0');
2481template <
typename Char,
typename UInt,
2482 FMT_ENABLE_IF(std::is_integral<UInt>::value)>
2483inline auto write_significand(Char* out, UInt significand,
int significand_size,
2484 int integral_size, Char decimal_point) -> Char* {
2486 return format_decimal(out, significand, significand_size).end;
2487 out += significand_size + 1;
2489 int floating_size = significand_size - integral_size;
2490 for (
int i = floating_size / 2; i > 0; --i) {
2492 copy2(out, digits2(
static_cast<std::size_t
>(significand % 100)));
2495 if (floating_size % 2 != 0) {
2496 *--out =
static_cast<Char
>(
'0' + significand % 10);
2499 *--out = decimal_point;
2500 format_decimal(out - integral_size, significand, integral_size);
2504template <
typename OutputIt,
typename UInt,
typename Char,
2505 FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)>
2506inline auto write_significand(OutputIt out, UInt significand,
2507 int significand_size,
int integral_size,
2508 Char decimal_point) -> OutputIt {
2510 Char
buffer[digits10<UInt>() + 2];
2511 auto end = write_significand(
buffer, significand, significand_size,
2512 integral_size, decimal_point);
2513 return detail::copy_noinline<Char>(
buffer, end, out);
2516template <
typename OutputIt,
typename Char>
2517FMT_CONSTEXPR
auto write_significand(OutputIt out,
const char* significand,
2518 int significand_size,
int integral_size,
2519 Char decimal_point) -> OutputIt {
2520 out = detail::copy_noinline<Char>(significand, significand + integral_size,
2522 if (!decimal_point)
return out;
2523 *out++ = decimal_point;
2524 return detail::copy_noinline<Char>(significand + integral_size,
2525 significand + significand_size, out);
2528template <
typename OutputIt,
typename Char,
typename T,
typename Grouping>
2529FMT_CONSTEXPR20
auto write_significand(OutputIt out, T significand,
2530 int significand_size,
int integral_size,
2532 const Grouping& grouping) -> OutputIt {
2533 if (!grouping.has_separator()) {
2534 return write_significand(out, significand, significand_size, integral_size,
2537 auto buffer = basic_memory_buffer<Char>();
2538 write_significand(basic_appender<Char>(
buffer), significand, significand_size,
2539 integral_size, decimal_point);
2541 out, basic_string_view<Char>(
buffer.
data(), to_unsigned(integral_size)));
2542 return detail::copy_noinline<Char>(
buffer.
data() + integral_size,
2546template <
typename Char,
typename OutputIt,
typename DecimalFP,
2548FMT_CONSTEXPR20
auto do_write_float(OutputIt out,
const DecimalFP& f,
2549 const format_specs& specs,
2552 auto significand = f.significand;
2553 int significand_size = get_significand_size(f);
2554 const Char zero =
static_cast<Char
>(
'0');
2555 auto sign = fspecs.sign;
2556 size_t size = to_unsigned(significand_size) + (sign ? 1 : 0);
2557 using iterator = reserve_iterator<OutputIt>;
2559 Char decimal_point =
2560 fspecs.locale ? detail::decimal_point<Char>(loc) : static_cast<Char>(
'.');
2562 int output_exp = f.exponent + significand_size - 1;
2563 auto use_exp_format = [=]() {
2564 if (fspecs.format == float_format::exp)
return true;
2565 if (fspecs.format != float_format::general)
return false;
2568 const int exp_lower = -4, exp_upper = 16;
2569 return output_exp < exp_lower ||
2570 output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper);
2572 if (use_exp_format()) {
2574 if (fspecs.showpoint) {
2575 num_zeros = fspecs.precision - significand_size;
2576 if (num_zeros < 0) num_zeros = 0;
2577 size += to_unsigned(num_zeros);
2578 }
else if (significand_size == 1) {
2579 decimal_point = Char();
2581 auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp;
2583 if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3;
2585 size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits);
2586 char exp_char = specs.upper ?
'E' :
'e';
2587 auto write = [=](iterator it) {
2588 if (sign) *it++ = detail::sign<Char>(sign);
2590 it = write_significand(it, significand, significand_size, 1,
2592 if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero);
2593 *it++ =
static_cast<Char
>(exp_char);
2594 return write_exponent<Char>(output_exp, it);
2596 return specs.width > 0
2597 ? write_padded<Char, align::right>(out, specs, size, write)
2598 : base_iterator(out, write(reserve(out, size)));
2601 int exp = f.exponent + significand_size;
2602 if (f.exponent >= 0) {
2604 size += to_unsigned(f.exponent);
2605 int num_zeros = fspecs.precision - exp;
2606 abort_fuzzing_if(num_zeros > 5000);
2607 if (fspecs.showpoint) {
2609 if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 0;
2610 if (num_zeros > 0) size += to_unsigned(num_zeros);
2612 auto grouping = Grouping(loc, fspecs.locale);
2613 size += to_unsigned(grouping.count_separators(exp));
2614 return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
2615 if (sign) *it++ = detail::sign<Char>(sign);
2616 it = write_significand<Char>(it, significand, significand_size,
2617 f.exponent, grouping);
2618 if (!fspecs.showpoint) return it;
2619 *it++ = decimal_point;
2620 return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
2622 }
else if (exp > 0) {
2624 int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0;
2625 size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0);
2626 auto grouping = Grouping(loc, fspecs.locale);
2627 size += to_unsigned(grouping.count_separators(exp));
2628 return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
2629 if (sign) *it++ = detail::sign<Char>(sign);
2630 it = write_significand(it, significand, significand_size, exp,
2631 decimal_point, grouping);
2632 return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
2636 int num_zeros = -exp;
2637 if (significand_size == 0 && fspecs.precision >= 0 &&
2638 fspecs.precision < num_zeros) {
2639 num_zeros = fspecs.precision;
2641 bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint;
2642 size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros);
2643 return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
2644 if (sign) *it++ = detail::sign<Char>(sign);
2646 if (!pointy)
return it;
2647 *it++ = decimal_point;
2648 it = detail::fill_n(it, num_zeros, zero);
2649 return write_significand<Char>(it, significand, significand_size);
2653template <
typename Char>
class fallback_digit_grouping {
2655 constexpr fallback_digit_grouping(
locale_ref,
bool) {}
2657 constexpr auto has_separator()
const ->
bool {
return false; }
2659 constexpr auto count_separators(
int)
const ->
int {
return 0; }
2661 template <
typename Out,
typename C>
2667template <
typename Char,
typename OutputIt,
typename DecimalFP>
2668FMT_CONSTEXPR20
auto write_float(OutputIt out,
const DecimalFP& f,
2671 if (is_constant_evaluated()) {
2672 return do_write_float<Char, OutputIt, DecimalFP,
2676 return do_write_float<Char>(out, f, specs, fspecs, loc);
2680template <
typename T>
constexpr auto isnan(T value) ->
bool {
2681 return value != value;
2684template <
typename T,
typename Enable =
void>
2687template <
typename T>
2689 : std::true_type {};
2691template <
typename T, FMT_ENABLE_IF(std::is_
floating_po
int<T>::value&&
2692 has_isfinite<T>::value)>
2693FMT_CONSTEXPR20
auto isfinite(T
value) ->
bool {
2694 constexpr T inf = T(std::numeric_limits<double>::infinity());
2695 if (is_constant_evaluated())
2696 return !detail::isnan(
value) && value < inf && value > -inf;
2697 return std::isfinite(
value);
2699template <
typename T, FMT_ENABLE_IF(!has_isfinite<T>::value)>
2700FMT_CONSTEXPR
auto isfinite(T value) ->
bool {
2701 T inf = T(std::numeric_limits<double>::infinity());
2703 return !detail::isnan(value) && value < inf && value > -inf;
2706template <
typename T, FMT_ENABLE_IF(is_
floating_po
int<T>::value)>
2707FMT_INLINE FMT_CONSTEXPR
bool signbit(T value) {
2708 if (is_constant_evaluated()) {
2709#ifdef __cpp_if_constexpr
2710 if constexpr (std::numeric_limits<double>::is_iec559) {
2711 auto bits = detail::bit_cast<uint64_t>(
static_cast<double>(value));
2712 return (bits >> (num_bits<uint64_t>() - 1)) != 0;
2716 return std::signbit(
static_cast<double>(value));
2719inline FMT_CONSTEXPR20
void adjust_precision(
int& precision,
int exp10) {
2722 if (exp10 > 0 && precision > max_value<int>() - exp10)
2723 FMT_THROW(format_error(
"number is too big"));
2731 using bigit = uint32_t;
2732 using double_bigit = uint64_t;
2733 enum { bigits_capacity = 32 };
2737 FMT_CONSTEXPR20
auto operator[](
int index)
const -> bigit {
2738 return bigits_[to_unsigned(index)];
2740 FMT_CONSTEXPR20
auto operator[](
int index) -> bigit& {
2741 return bigits_[to_unsigned(index)];
2744 static constexpr const int bigit_bits = num_bits<bigit>();
2748 FMT_CONSTEXPR20
void subtract_bigits(
int index, bigit other, bigit& borrow) {
2749 auto result =
static_cast<double_bigit
>((*this)[index]) - other - borrow;
2750 (*this)[index] =
static_cast<bigit
>(result);
2751 borrow =
static_cast<bigit
>(result >> (bigit_bits * 2 - 1));
2754 FMT_CONSTEXPR20
void remove_leading_zeros() {
2755 int num_bigits =
static_cast<int>(bigits_.size()) - 1;
2756 while (num_bigits > 0 && (*
this)[num_bigits] == 0) --num_bigits;
2757 bigits_.resize(to_unsigned(num_bigits + 1));
2761 FMT_CONSTEXPR20
void subtract_aligned(
const bigint& other) {
2762 FMT_ASSERT(other.exp_ >= exp_,
"unaligned bigints");
2763 FMT_ASSERT(compare(*
this, other) >= 0,
"");
2765 int i = other.exp_ - exp_;
2766 for (
size_t j = 0, n = other.bigits_.
size(); j != n; ++i, ++j)
2767 subtract_bigits(i, other.bigits_[j], borrow);
2768 while (borrow > 0) subtract_bigits(i, 0, borrow);
2769 remove_leading_zeros();
2772 FMT_CONSTEXPR20
void multiply(uint32_t
value) {
2773 const double_bigit wide_value =
value;
2775 for (
size_t i = 0, n = bigits_.size(); i < n; ++i) {
2776 double_bigit result = bigits_[i] * wide_value + carry;
2777 bigits_[i] =
static_cast<bigit
>(result);
2778 carry =
static_cast<bigit
>(result >> bigit_bits);
2780 if (carry != 0) bigits_.push_back(carry);
2783 template <
typename UInt, FMT_ENABLE_IF(std::is_same<UInt, u
int64_t>::value ||
2784 std::is_same<UInt, u
int128_t>::value)>
2785 FMT_CONSTEXPR20
void multiply(UInt
value) {
2787 conditional_t<std::is_same<UInt, uint128_t>::value, uint64_t, uint32_t>;
2788 const int shift = num_bits<half_uint>() - bigit_bits;
2789 const UInt lower =
static_cast<half_uint
>(
value);
2790 const UInt upper =
value >> num_bits<half_uint>();
2792 for (
size_t i = 0, n = bigits_.size(); i < n; ++i) {
2793 UInt result = lower * bigits_[i] +
static_cast<bigit
>(carry);
2794 carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) +
2795 (carry >> bigit_bits);
2796 bigits_[i] =
static_cast<bigit
>(result);
2798 while (carry != 0) {
2799 bigits_.push_back(
static_cast<bigit
>(carry));
2800 carry >>= bigit_bits;
2804 template <
typename UInt, FMT_ENABLE_IF(std::is_same<UInt, u
int64_t>::value ||
2805 std::is_same<UInt, u
int128_t>::value)>
2806 FMT_CONSTEXPR20
void assign(UInt n) {
2807 size_t num_bigits = 0;
2809 bigits_[num_bigits++] =
static_cast<bigit
>(n);
2812 bigits_.resize(num_bigits);
2817 FMT_CONSTEXPR20 bigint() : exp_(0) {}
2818 explicit bigint(uint64_t n) { assign(n); }
2820 bigint(
const bigint&) =
delete;
2821 void operator=(
const bigint&) =
delete;
2823 FMT_CONSTEXPR20
void assign(
const bigint& other) {
2824 auto size = other.bigits_.
size();
2825 bigits_.resize(size);
2826 auto data = other.bigits_.
data();
2827 copy<bigit>(data, data + size, bigits_.data());
2831 template <
typename Int> FMT_CONSTEXPR20
void operator=(Int n) {
2832 FMT_ASSERT(n > 0,
"");
2833 assign(uint64_or_128_t<Int>(n));
2836 FMT_CONSTEXPR20
auto num_bigits()
const ->
int {
2837 return static_cast<int>(bigits_.size()) + exp_;
2840 FMT_NOINLINE FMT_CONSTEXPR20
auto operator<<=(
int shift) -> bigint& {
2841 FMT_ASSERT(shift >= 0,
"");
2842 exp_ += shift / bigit_bits;
2843 shift %= bigit_bits;
2844 if (shift == 0)
return *
this;
2846 for (
size_t i = 0, n = bigits_.size(); i < n; ++i) {
2847 bigit c = bigits_[i] >> (bigit_bits - shift);
2848 bigits_[i] = (bigits_[i] << shift) + carry;
2851 if (carry != 0) bigits_.push_back(carry);
2855 template <
typename Int>
2856 FMT_CONSTEXPR20
auto operator*=(Int
value) -> bigint& {
2857 FMT_ASSERT(
value > 0,
"");
2858 multiply(uint32_or_64_or_128_t<Int>(
value));
2862 friend FMT_CONSTEXPR20
auto compare(
const bigint& lhs,
const bigint& rhs)
2864 int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits();
2865 if (num_lhs_bigits != num_rhs_bigits)
2866 return num_lhs_bigits > num_rhs_bigits ? 1 : -1;
2867 int i =
static_cast<int>(lhs.bigits_.
size()) - 1;
2868 int j =
static_cast<int>(rhs.bigits_.
size()) - 1;
2870 if (end < 0) end = 0;
2871 for (; i >= end; --i, --j) {
2872 bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j];
2873 if (lhs_bigit != rhs_bigit)
return lhs_bigit > rhs_bigit ? 1 : -1;
2875 if (i != j)
return i > j ? 1 : -1;
2880 friend FMT_CONSTEXPR20
auto add_compare(
const bigint& lhs1,
2881 const bigint& lhs2,
const bigint& rhs)
2883 auto minimum = [](
int a,
int b) {
return a < b ? a : b; };
2884 auto maximum = [](
int a,
int b) {
return a > b ? a : b; };
2885 int max_lhs_bigits = maximum(lhs1.num_bigits(), lhs2.num_bigits());
2886 int num_rhs_bigits = rhs.num_bigits();
2887 if (max_lhs_bigits + 1 < num_rhs_bigits)
return -1;
2888 if (max_lhs_bigits > num_rhs_bigits)
return 1;
2889 auto get_bigit = [](
const bigint& n,
int i) -> bigit {
2890 return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0;
2892 double_bigit borrow = 0;
2893 int min_exp = minimum(minimum(lhs1.exp_, lhs2.exp_), rhs.exp_);
2894 for (
int i = num_rhs_bigits - 1; i >= min_exp; --i) {
2896 static_cast<double_bigit
>(get_bigit(lhs1, i)) + get_bigit(lhs2, i);
2897 bigit rhs_bigit = get_bigit(rhs, i);
2898 if (sum > rhs_bigit + borrow)
return 1;
2899 borrow = rhs_bigit + borrow - sum;
2900 if (borrow > 1)
return -1;
2901 borrow <<= bigit_bits;
2903 return borrow != 0 ? -1 : 0;
2907 FMT_CONSTEXPR20
void assign_pow10(
int exp) {
2908 FMT_ASSERT(exp >= 0,
"");
2909 if (exp == 0)
return *
this = 1;
2912 while (exp >= bitmask) bitmask <<= 1;
2918 while (bitmask != 0) {
2920 if ((exp & bitmask) != 0) *
this *= 5;
2926 FMT_CONSTEXPR20
void square() {
2927 int num_bigits =
static_cast<int>(bigits_.size());
2928 int num_result_bigits = 2 * num_bigits;
2930 bigits_.resize(to_unsigned(num_result_bigits));
2931 auto sum = uint128_t();
2932 for (
int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) {
2935 for (
int i = 0, j = bigit_index; j >= 0; ++i, --j) {
2937 sum +=
static_cast<double_bigit
>(n[i]) * n[j];
2939 (*this)[bigit_index] =
static_cast<bigit
>(sum);
2940 sum >>= num_bits<bigit>();
2943 for (
int bigit_index = num_bigits; bigit_index < num_result_bigits;
2945 for (
int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;)
2946 sum +=
static_cast<double_bigit
>(n[i++]) * n[j--];
2947 (*this)[bigit_index] =
static_cast<bigit
>(sum);
2948 sum >>= num_bits<bigit>();
2950 remove_leading_zeros();
2956 FMT_CONSTEXPR20
void align(
const bigint& other) {
2957 int exp_difference = exp_ - other.exp_;
2958 if (exp_difference <= 0)
return;
2959 int num_bigits =
static_cast<int>(bigits_.size());
2960 bigits_.resize(to_unsigned(num_bigits + exp_difference));
2961 for (
int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j)
2962 bigits_[j] = bigits_[i];
2963 memset(bigits_.data(), 0, to_unsigned(exp_difference) *
sizeof(bigit));
2964 exp_ -= exp_difference;
2969 FMT_CONSTEXPR20
auto divmod_assign(
const bigint& divisor) ->
int {
2970 FMT_ASSERT(
this != &divisor,
"");
2971 if (compare(*
this, divisor) < 0)
return 0;
2972 FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0,
"");
2976 subtract_aligned(divisor);
2978 }
while (compare(*
this, divisor) >= 0);
2985 predecessor_closer = 1,
2993FMT_CONSTEXPR20
inline void format_dragon(basic_fp<uint128_t> value,
2994 unsigned flags,
int num_digits,
2995 buffer<char>& buf,
int& exp10) {
3001 bigint* upper =
nullptr;
3005 bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0;
3006 int shift = is_predecessor_closer ? 2 : 1;
3008 numerator = value.f;
3009 numerator <<= value.e + shift;
3012 if (is_predecessor_closer) {
3014 upper_store <<= value.e + 1;
3015 upper = &upper_store;
3017 denominator.assign_pow10(exp10);
3018 denominator <<= shift;
3019 }
else if (exp10 < 0) {
3020 numerator.assign_pow10(-exp10);
3021 lower.assign(numerator);
3022 if (is_predecessor_closer) {
3023 upper_store.assign(numerator);
3025 upper = &upper_store;
3027 numerator *= value.f;
3028 numerator <<= shift;
3030 denominator <<= shift - value.e;
3032 numerator = value.f;
3033 numerator <<= shift;
3034 denominator.assign_pow10(exp10);
3035 denominator <<= shift - value.e;
3037 if (is_predecessor_closer) {
3038 upper_store = 1ULL << 1;
3039 upper = &upper_store;
3042 int even =
static_cast<int>((value.f & 1) == 0);
3043 if (!upper) upper = &lower;
3044 bool shortest = num_digits < 0;
3045 if ((flags & dragon::fixup) != 0) {
3046 if (add_compare(numerator, *upper, denominator) + even <= 0) {
3049 if (num_digits < 0) {
3051 if (upper != &lower) *upper *= 10;
3054 if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1);
3060 char* data = buf.data();
3062 int digit = numerator.divmod_assign(denominator);
3063 bool low = compare(numerator, lower) - even < 0;
3065 bool high = add_compare(numerator, *upper, denominator) + even > 0;
3066 data[num_digits++] =
static_cast<char>(
'0' + digit);
3069 ++data[num_digits - 1];
3071 int result = add_compare(numerator, numerator, denominator);
3073 if (result > 0 || (result == 0 && (digit % 2) != 0))
3074 ++data[num_digits - 1];
3076 buf.try_resize(to_unsigned(num_digits));
3077 exp10 -= num_digits - 1;
3082 if (upper != &lower) *upper *= 10;
3086 exp10 -= num_digits - 1;
3087 if (num_digits <= 0) {
3089 if (num_digits == 0) {
3091 digit = add_compare(numerator, numerator, denominator) > 0 ?
'1' :
'0';
3093 buf.push_back(digit);
3096 buf.try_resize(to_unsigned(num_digits));
3097 for (
int i = 0; i < num_digits - 1; ++i) {
3098 int digit = numerator.divmod_assign(denominator);
3099 buf[i] =
static_cast<char>(
'0' + digit);
3102 int digit = numerator.divmod_assign(denominator);
3103 auto result = add_compare(numerator, numerator, denominator);
3104 if (result > 0 || (result == 0 && (digit % 2) != 0)) {
3106 const auto overflow =
'0' + 10;
3107 buf[num_digits - 1] = overflow;
3109 for (
int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) {
3113 if (buf[0] == overflow) {
3115 if ((flags & dragon::fixed) != 0)
3124 buf[num_digits - 1] =
static_cast<char>(
'0' + digit);
3128template <
typename Float, FMT_ENABLE_IF(!is_
double_
double<Float>::value)>
3129FMT_CONSTEXPR20
void format_hexfloat(Float value,
format_specs specs,
3130 buffer<char>& buf) {
3133 static_assert(!std::is_same<Float, float>::value,
"");
3135 using info = dragonbox::float_info<Float>;
3138 using carrier_uint =
typename info::carrier_uint;
3140 constexpr auto num_float_significand_bits =
3141 detail::num_significand_bits<Float>();
3143 basic_fp<carrier_uint> f(value);
3144 f.e += num_float_significand_bits;
3145 if (!has_implicit_bit<Float>()) --f.e;
3147 constexpr auto num_fraction_bits =
3148 num_float_significand_bits + (has_implicit_bit<Float>() ? 1 : 0);
3149 constexpr auto num_xdigits = (num_fraction_bits + 3) / 4;
3151 constexpr auto leading_shift = ((num_xdigits - 1) * 4);
3152 const auto leading_mask = carrier_uint(0xF) << leading_shift;
3153 const auto leading_xdigit =
3154 static_cast<uint32_t
>((f.f & leading_mask) >> leading_shift);
3155 if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1);
3157 int print_xdigits = num_xdigits - 1;
3158 if (specs.precision >= 0 && print_xdigits > specs.precision) {
3159 const int shift = ((print_xdigits - specs.precision - 1) * 4);
3160 const auto mask = carrier_uint(0xF) << shift;
3161 const auto v =
static_cast<uint32_t
>((f.f & mask) >> shift);
3164 const auto inc = carrier_uint(1) << (shift + 4);
3170 if (!has_implicit_bit<Float>()) {
3171 const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
3172 if ((f.f & implicit_bit) == implicit_bit) {
3178 print_xdigits = specs.precision;
3181 char xdigits[num_bits<carrier_uint>() / 4];
3182 detail::fill_n(xdigits,
sizeof(xdigits),
'0');
3183 format_uint<4>(xdigits, f.f, num_xdigits, specs.upper);
3186 while (print_xdigits > 0 && xdigits[print_xdigits] ==
'0') --print_xdigits;
3189 buf.push_back(specs.upper ?
'X' :
'x');
3190 buf.push_back(xdigits[0]);
3191 if (specs.alt || print_xdigits > 0 || print_xdigits < specs.precision)
3193 buf.append(xdigits + 1, xdigits + 1 + print_xdigits);
3194 for (; print_xdigits < specs.precision; ++print_xdigits) buf.push_back(
'0');
3196 buf.push_back(specs.upper ?
'P' :
'p');
3201 abs_e =
static_cast<uint32_t
>(-f.e);
3204 abs_e =
static_cast<uint32_t
>(f.e);
3206 format_decimal<char>(appender(buf), abs_e, detail::count_digits(abs_e));
3209template <
typename Float, FMT_ENABLE_IF(is_
double_
double<Float>::value)>
3210FMT_CONSTEXPR20
void format_hexfloat(Float value,
format_specs specs,
3211 buffer<char>& buf) {
3212 format_hexfloat(
static_cast<double>(value), specs, buf);
3215constexpr auto fractional_part_rounding_thresholds(
int index) -> uint32_t {
3222 return U
"\x9999999a\x828f5c29\x80418938\x80068db9\x8000a7c6\x800010c7"
3223 U
"\x800001ae\x8000002b"[index];
3226template <
typename Float>
3227FMT_CONSTEXPR20
auto format_float(Float value,
int precision, float_specs specs,
3228 buffer<char>& buf) ->
int {
3230 static_assert(!std::is_same<Float, float>::value,
"");
3231 FMT_ASSERT(value >= 0,
"value is negative");
3232 auto converted_value = convert_float(value);
3234 const bool fixed = specs.format == float_format::fixed;
3236 if (precision <= 0 || !fixed) {
3240 buf.try_resize(to_unsigned(precision));
3241 fill_n(buf.data(), precision,
'0');
3246 bool use_dragon =
true;
3247 unsigned dragon_flags = 0;
3248 if (!is_fast_float<Float>() || is_constant_evaluated()) {
3249 const auto inv_log2_10 = 0.3010299956639812;
3250 using info = dragonbox::float_info<
decltype(converted_value)>;
3251 const auto f = basic_fp<typename info::carrier_uint>(converted_value);
3256 auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10;
3257 exp =
static_cast<int>(e);
3259 dragon_flags = dragon::fixup;
3260 }
else if (precision < 0) {
3262 if (specs.binary32) {
3263 auto dec = dragonbox::to_decimal(
static_cast<float>(value));
3264 write<char>(appender(buf), dec.significand);
3265 return dec.exponent;
3267 auto dec = dragonbox::to_decimal(
static_cast<double>(value));
3268 write<char>(appender(buf), dec.significand);
3269 return dec.exponent;
3272 using info = dragonbox::float_info<double>;
3273 auto br = bit_cast<uint64_t>(
static_cast<double>(value));
3275 const uint64_t significand_mask =
3276 (
static_cast<uint64_t
>(1) << num_significand_bits<double>()) - 1;
3277 uint64_t significand = (br & significand_mask);
3278 int exponent =
static_cast<int>((br & exponent_mask<double>()) >>
3279 num_significand_bits<double>());
3281 if (exponent != 0) {
3282 exponent -= exponent_bias<double>() + num_significand_bits<double>();
3284 (
static_cast<uint64_t
>(1) << num_significand_bits<double>());
3288 FMT_ASSERT(significand != 0,
"zeros should not appear here");
3289 int shift = countl_zero(significand);
3290 FMT_ASSERT(shift >= num_bits<uint64_t>() - num_significand_bits<double>(),
3292 shift -= (num_bits<uint64_t>() - num_significand_bits<double>() - 2);
3293 exponent = (std::numeric_limits<double>::min_exponent -
3294 num_significand_bits<double>()) -
3296 significand <<= shift;
3301 const int k = info::kappa - dragonbox::floor_log10_pow2(exponent);
3303 const int beta = exponent + dragonbox::floor_log2_pow10(k);
3304 uint64_t first_segment;
3305 bool has_more_segments;
3306 int digits_in_the_first_segment;
3308 const auto r = dragonbox::umul192_upper128(
3309 significand << beta, dragonbox::get_cached_power(k));
3310 first_segment = r.high();
3311 has_more_segments = r.low() != 0;
3314 if (first_segment >= 1000000000000000000ULL) {
3315 digits_in_the_first_segment = 19;
3319 digits_in_the_first_segment = 18;
3320 first_segment *= 10;
3325 if (fixed) adjust_precision(precision, exp + digits_in_the_first_segment);
3329 if (digits_in_the_first_segment > precision) {
3332 if (precision <= 0) {
3333 exp += digits_in_the_first_segment;
3335 if (precision < 0) {
3341 if ((first_segment |
static_cast<uint64_t
>(has_more_segments)) >
3342 5000000000000000000ULL) {
3350 exp += digits_in_the_first_segment - precision;
3359 const uint32_t first_subsegment =
static_cast<uint32_t
>(
3360 dragonbox::umul128_upper64(first_segment, 7922816251426433760ULL) >>
3362 const uint64_t second_third_subsegments =
3363 first_segment - first_subsegment * 10000000000ULL;
3367 bool should_round_up;
3368 int number_of_digits_to_print = precision > 9 ? 9 : precision;
3371 auto print_subsegment = [&](uint32_t subsegment,
char* buffer) {
3372 int number_of_digits_printed = 0;
3375 if ((number_of_digits_to_print & 1) != 0) {
3381 prod = ((subsegment *
static_cast<uint64_t
>(720575941)) >> 24) + 1;
3382 digits =
static_cast<uint32_t
>(prod >> 32);
3383 *buffer =
static_cast<char>(
'0' + digits);
3384 number_of_digits_printed++;
3394 prod = ((subsegment *
static_cast<uint64_t
>(450359963)) >> 20) + 1;
3395 digits =
static_cast<uint32_t
>(prod >> 32);
3396 copy2(buffer, digits2(digits));
3397 number_of_digits_printed += 2;
3401 while (number_of_digits_printed < number_of_digits_to_print) {
3402 prod =
static_cast<uint32_t
>(prod) *
static_cast<uint64_t
>(100);
3403 digits =
static_cast<uint32_t
>(prod >> 32);
3404 copy2(buffer + number_of_digits_printed, digits2(digits));
3405 number_of_digits_printed += 2;
3410 print_subsegment(first_subsegment, buf.data());
3414 if (precision <= 9) {
3428 if (precision < 9) {
3429 uint32_t fractional_part =
static_cast<uint32_t
>(prod);
3431 fractional_part >= fractional_part_rounding_thresholds(
3432 8 - number_of_digits_to_print) ||
3433 ((fractional_part >> 31) &
3434 ((digits & 1) | (second_third_subsegments != 0) |
3435 has_more_segments)) != 0;
3443 should_round_up = second_third_subsegments > 5000000000ULL ||
3444 (second_third_subsegments == 5000000000ULL &&
3445 ((digits & 1) != 0 || has_more_segments));
3454 const uint32_t second_subsegment =
3455 static_cast<uint32_t
>(dragonbox::umul128_upper64(
3456 second_third_subsegments, 1844674407370955162ULL));
3457 const uint32_t third_subsegment =
3458 static_cast<uint32_t
>(second_third_subsegments) -
3459 second_subsegment * 10;
3461 number_of_digits_to_print = precision - 9;
3462 print_subsegment(second_subsegment, buf.data() + 9);
3465 if (precision < 18) {
3469 uint32_t fractional_part =
static_cast<uint32_t
>(prod);
3471 fractional_part >= fractional_part_rounding_thresholds(
3472 8 - number_of_digits_to_print) ||
3473 ((fractional_part >> 31) &
3474 ((digits & 1) | (third_subsegment != 0) |
3475 has_more_segments)) != 0;
3482 should_round_up = third_subsegment > 5 ||
3483 (third_subsegment == 5 &&
3484 ((digits & 1) != 0 || has_more_segments));
3489 if (should_round_up) {
3490 ++buf[precision - 1];
3491 for (
int i = precision - 1; i > 0 && buf[i] >
'9'; --i) {
3498 buf[precision++] =
'0';
3503 buf.try_resize(to_unsigned(precision));
3508 exp += digits_in_the_first_segment - 1;
3512 auto f = basic_fp<uint128_t>();
3513 bool is_predecessor_closer = specs.binary32
3514 ? f.assign(
static_cast<float>(value))
3515 : f.assign(converted_value);
3516 if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer;
3517 if (fixed) dragon_flags |= dragon::fixed;
3520 const int max_double_digits = 767;
3521 if (precision > max_double_digits) precision = max_double_digits;
3522 format_dragon(f, dragon_flags, precision, buf, exp);
3524 if (!fixed && !specs.showpoint) {
3526 auto num_digits = buf.size();
3527 while (num_digits > 0 && buf[num_digits - 1] ==
'0') {
3531 buf.try_resize(num_digits);
3536template <
typename Char,
typename OutputIt,
typename T>
3537FMT_CONSTEXPR20
auto write_float(OutputIt out, T value,
format_specs specs,
3538 locale_ref loc) -> OutputIt {
3539 sign_t sign = specs.sign;
3540 if (detail::signbit(value)) {
3543 }
else if (sign == sign::minus) {
3547 if (!detail::isfinite(value))
3548 return write_nonfinite<Char>(out, detail::isnan(value), specs, sign);
3550 if (specs.align == align::numeric && sign) {
3551 auto it = reserve(out, 1);
3552 *it++ = detail::sign<Char>(sign);
3553 out = base_iterator(out, it);
3555 if (specs.width != 0) --specs.width;
3558 memory_buffer buffer;
3559 if (specs.type == presentation_type::hexfloat) {
3560 if (sign) buffer.push_back(detail::sign<char>(sign));
3561 format_hexfloat(convert_float(value), specs, buffer);
3562 return write_bytes<Char, align::right>(out, {buffer.
data(), buffer.
size()},
3566 int precision = specs.precision >= 0 || specs.type == presentation_type::none
3569 if (specs.type == presentation_type::exp) {
3570 if (precision == max_value<int>())
3571 report_error(
"number is too big");
3574 }
else if (specs.type != presentation_type::fixed && precision == 0) {
3577 float_specs fspecs = parse_float_type_spec(specs);
3579 if (const_check(std::is_same<T, float>())) fspecs.binary32 =
true;
3580 int exp = format_float(convert_float(value), precision, fspecs, buffer);
3581 fspecs.precision = precision;
3582 auto f = big_decimal_fp{buffer.
data(),
static_cast<int>(buffer.
size()), exp};
3583 return write_float<Char>(out, f, specs, fspecs, loc);
3586template <
typename Char,
typename OutputIt,
typename T,
3587 FMT_ENABLE_IF(is_floating_point<T>::value)>
3588FMT_CONSTEXPR20
auto write(OutputIt out, T value,
format_specs specs,
3589 locale_ref loc = {}) -> OutputIt {
3590 if (const_check(!is_supported_floating_point(value)))
return out;
3591 return specs.localized && write_loc(out, value, specs, loc)
3593 : write_float<Char>(out, value, specs, loc);
3596template <
typename Char,
typename OutputIt,
typename T,
3597 FMT_ENABLE_IF(is_fast_float<T>::value)>
3598FMT_CONSTEXPR20
auto write(OutputIt out, T value) -> OutputIt {
3599 if (is_constant_evaluated())
return write<Char>(out, value,
format_specs());
3600 if (const_check(!is_supported_floating_point(value)))
return out;
3602 auto sign = sign_t::none;
3603 if (detail::signbit(value)) {
3609 using floaty = conditional_t<std::is_same<T, long double>::value, double, T>;
3610 using floaty_uint =
typename dragonbox::float_info<floaty>::carrier_uint;
3611 floaty_uint mask = exponent_mask<floaty>();
3612 if ((bit_cast<floaty_uint>(value) & mask) == mask)
3613 return write_nonfinite<Char>(out, std::isnan(value), specs, sign);
3615 auto fspecs = float_specs();
3617 auto dec = dragonbox::to_decimal(
static_cast<floaty
>(value));
3618 return write_float<Char>(out, dec, specs, fspecs, {});
3621template <
typename Char,
typename OutputIt,
typename T,
3622 FMT_ENABLE_IF(is_floating_point<T>::value &&
3623 !is_fast_float<T>::value)>
3624inline auto write(OutputIt out, T value) -> OutputIt {
3628template <
typename Char,
typename OutputIt>
3631 FMT_ASSERT(
false,
"");
3635template <
typename Char,
typename OutputIt>
3638 return copy_noinline<Char>(value.begin(), value.end(), out);
3641template <
typename Char,
typename OutputIt,
typename T,
3642 FMT_ENABLE_IF(has_to_string_view<T>::value)>
3643constexpr auto write(OutputIt out,
const T& value) -> OutputIt {
3644 return write<Char>(out, to_string_view(value));
3649 typename Char,
typename OutputIt,
typename T,
3651 std::is_enum<T>::value && !std::is_same<T, Char>::value &&
3652 mapped_type_constant<T, basic_format_context<OutputIt, Char>>::value !=
3654 FMT_ENABLE_IF(check)>
3655FMT_CONSTEXPR
auto write(OutputIt out, T value) -> OutputIt {
3656 return write<Char>(out,
static_cast<underlying_t<T>
>(value));
3659template <
typename Char,
typename OutputIt,
typename T,
3660 FMT_ENABLE_IF(std::is_same<T, bool>::value)>
3661FMT_CONSTEXPR
auto write(OutputIt out, T value,
const format_specs& specs = {},
3662 locale_ref = {}) -> OutputIt {
3663 return specs.type != presentation_type::none &&
3664 specs.type != presentation_type::string
3665 ? write<Char>(out, value ? 1 : 0, specs, {})
3666 : write_bytes<Char>(out, value ?
"true" :
"false", specs);
3669template <
typename Char,
typename OutputIt>
3670FMT_CONSTEXPR
auto write(OutputIt out, Char value) -> OutputIt {
3671 auto it = reserve(out, 1);
3673 return base_iterator(out, it);
3676template <
typename Char,
typename OutputIt>
3677FMT_CONSTEXPR20
auto write(OutputIt out,
const Char* value) -> OutputIt {
3679 report_error(
"string pointer is null");
3683template <
typename Char,
typename OutputIt,
typename T,
3684 FMT_ENABLE_IF(std::is_same<T, void>::value)>
3685auto write(OutputIt out,
const T* value,
const format_specs& specs = {},
3686 locale_ref = {}) -> OutputIt {
3687 return write_ptr<Char>(out, bit_cast<uintptr_t>(value), &specs);
3691template <
typename Char,
typename OutputIt,
typename T,
3692 typename Context = basic_format_context<OutputIt, Char>>
3693FMT_CONSTEXPR
auto write(OutputIt out,
const T& value) -> enable_if_t<
3694 std::is_class<T>::value && !has_to_string_view<T>::value &&
3695 !is_floating_point<T>::value && !std::is_same<T, Char>::value &&
3696 !std::is_same<T, remove_cvref_t<decltype(arg_mapper<Context>().map(
3699 return write<Char>(out, arg_mapper<Context>().map(value));
3702template <
typename Char,
typename OutputIt,
typename T,
3703 typename Context = basic_format_context<OutputIt, Char>>
3704FMT_CONSTEXPR
auto write(OutputIt out,
const T& value)
3705 -> enable_if_t<mapped_type_constant<T, Context>::value ==
3706 type::custom_type &&
3707 !std::is_fundamental<T>::value,
3709 auto formatter =
typename Context::template formatter_type<T>();
3710 auto parse_ctx =
typename Context::parse_context_type({});
3712 auto ctx = Context(out, {}, {});
3720 using context = buffered_context<Char>;
3726 template <
typename T>
auto operator()(T
value) -> iterator {
3727 return write<Char>(out,
value);
3731 context format_ctx(out, args, loc);
3732 h.format(parse_ctx, format_ctx);
3733 return format_ctx.out();
3739 using context = buffered_context<Char>;
3745 template <
typename T>
3746 FMT_CONSTEXPR FMT_INLINE
auto operator()(T
value) -> iterator {
3747 return detail::write<Char>(out,
value, specs, locale);
3757 template <
typename T, FMT_ENABLE_IF(is_
integer<T>::value)>
3758 FMT_CONSTEXPR
auto operator()(T
value) ->
unsigned long long {
3759 if (is_negative(
value)) report_error(
"negative width");
3760 return static_cast<unsigned long long>(
value);
3763 template <
typename T, FMT_ENABLE_IF(!is_
integer<T>::value)>
3764 FMT_CONSTEXPR
auto operator()(T) ->
unsigned long long {
3765 report_error(
"width is not integer");
3771 template <
typename T, FMT_ENABLE_IF(is_
integer<T>::value)>
3772 FMT_CONSTEXPR
auto operator()(T
value) ->
unsigned long long {
3773 if (is_negative(
value)) report_error(
"negative precision");
3774 return static_cast<unsigned long long>(
value);
3777 template <
typename T, FMT_ENABLE_IF(!is_
integer<T>::value)>
3778 FMT_CONSTEXPR
auto operator()(T) ->
unsigned long long {
3779 report_error(
"precision is not integer");
3784template <
typename Handler,
typename FormatArg>
3785FMT_CONSTEXPR
auto get_dynamic_spec(FormatArg arg) ->
int {
3786 unsigned long long value = arg.visit(Handler());
3787 if (
value > to_unsigned(max_value<int>())) report_error(
"number is too big");
3788 return static_cast<int>(
value);
3791template <
typename Context,
typename ID>
3792FMT_CONSTEXPR
auto get_arg(Context& ctx, ID
id) ->
decltype(ctx.arg(
id)) {
3793 auto arg = ctx.arg(
id);
3794 if (!arg) report_error(
"argument not found");
3798template <
typename Handler,
typename Context>
3799FMT_CONSTEXPR
void handle_dynamic_spec(
int& value,
3800 arg_ref<typename Context::char_type> ref,
3803 case arg_id_kind::none:
3805 case arg_id_kind::index:
3806 value = detail::get_dynamic_spec<Handler>(get_arg(ctx, ref.val.index));
3808 case arg_id_kind::name:
3809 value = detail::get_dynamic_spec<Handler>(get_arg(ctx, ref.val.name));
3814#if FMT_USE_USER_DEFINED_LITERALS
3815# if FMT_USE_NONTYPE_TEMPLATE_ARGS
3816template <
typename T,
typename Char,
size_t N,
3817 fmt::detail_exported::fixed_string<Char, N> Str>
3818struct statically_named_arg : view {
3819 static constexpr auto name = Str.data;
3822 statically_named_arg(
const T& v) : value(v) {}
3825template <
typename T,
typename Char,
size_t N,
3826 fmt::detail_exported::fixed_string<Char, N> Str>
3827struct is_named_arg<statically_named_arg<T, Char, N, Str>> : std::true_type {};
3829template <
typename T,
typename Char,
size_t N,
3830 fmt::detail_exported::fixed_string<Char, N> Str>
3831struct is_statically_named_arg<statically_named_arg<T, Char, N, Str>>
3832 : std::true_type {};
3834template <
typename Char,
size_t N,
3835 fmt::detail_exported::fixed_string<Char, N> Str>
3837 template <
typename T>
auto operator=(T&& value)
const {
3838 return statically_named_arg<T, Char, N, Str>(std::forward<T>(value));
3842template <
typename Char>
struct udl_arg {
3845 template <
typename T>
auto operator=(T&& value)
const -> named_arg<Char, T> {
3846 return {str, std::forward<T>(value)};
3852template <
typename Locale,
typename Char>
3854 typename detail::vformat_args<Char>::type args)
3855 -> std::basic_string<Char> {
3858 return {buf.data(), buf.size()};
3863FMT_API
void format_error_code(buffer<char>& out,
int error_code,
3864 string_view message)
noexcept;
3866using fmt::report_error;
3867FMT_API
void report_error(format_func func,
int error_code,
3868 const char* message)
noexcept;
3872FMT_API
auto vsystem_error(
int error_code, string_view format_str,
3873 format_args args) -> std::system_error;
3890template <
typename... T>
3891auto system_error(
int error_code, format_string<T...> fmt, T&&... args)
3892 -> std::system_error {
3893 return vsystem_error(error_code, fmt, fmt::make_format_args(args...));
3910 const char* message)
noexcept;
3914FMT_API
void report_system_error(
int error_code,
const char* message)
noexcept;
3921 enum { buffer_size = std::numeric_limits<unsigned long long>::digits10 + 3 };
3922 mutable char buffer_[buffer_size];
3925 template <
typename UInt>
3926 FMT_CONSTEXPR20
auto format_unsigned(UInt value) ->
char* {
3927 auto n =
static_cast<detail::uint32_or_64_or_128_t<UInt>
>(value);
3928 return detail::format_decimal(buffer_, n, buffer_size - 1).begin;
3931 template <
typename Int>
3932 FMT_CONSTEXPR20
auto format_signed(Int value) ->
char* {
3933 auto abs_value =
static_cast<detail::uint32_or_64_or_128_t<Int>
>(value);
3934 bool negative = value < 0;
3935 if (negative) abs_value = 0 - abs_value;
3936 auto begin = format_unsigned(abs_value);
3937 if (negative) *--begin =
'-';
3942 explicit FMT_CONSTEXPR20 format_int(
int value) : str_(format_signed(value)) {}
3943 explicit FMT_CONSTEXPR20 format_int(
long value)
3944 : str_(format_signed(value)) {}
3945 explicit FMT_CONSTEXPR20 format_int(
long long value)
3946 : str_(format_signed(value)) {}
3947 explicit FMT_CONSTEXPR20 format_int(
unsigned value)
3948 : str_(format_unsigned(value)) {}
3949 explicit FMT_CONSTEXPR20 format_int(
unsigned long value)
3950 : str_(format_unsigned(value)) {}
3951 explicit FMT_CONSTEXPR20 format_int(
unsigned long long value)
3952 : str_(format_unsigned(value)) {}
3955 FMT_CONSTEXPR20
auto size() const ->
size_t {
3956 return detail::to_unsigned(buffer_ - str_ + buffer_size - 1);
3961 FMT_CONSTEXPR20
auto data() const -> const
char* {
return str_; }
3965 FMT_CONSTEXPR20
auto c_str() const -> const
char* {
3966 buffer_[buffer_size - 1] =
'\0';
3971 auto str() const -> std::
string {
return std::string(str_,
size()); }
3974template <
typename T,
typename Char>
3975struct formatter<T, Char, enable_if_t<detail::has_format_as<T>::value>>
3976 : formatter<detail::format_as_t<T>, Char> {
3977 template <
typename FormatContext>
3978 auto format(
const T& value, FormatContext& ctx)
const ->
decltype(ctx.out()) {
3979 auto&& val = format_as(value);
3980 return formatter<detail::format_as_t<T>, Char>::format(val, ctx);
3984#define FMT_FORMAT_AS(Type, Base) \
3985 template <typename Char> \
3986 struct formatter<Type, Char> : formatter<Base, Char> { \
3987 template <typename FormatContext> \
3988 auto format(Type value, FormatContext& ctx) const -> decltype(ctx.out()) { \
3989 return formatter<Base, Char>::format(value, ctx); \
3993FMT_FORMAT_AS(
signed char,
int);
3994FMT_FORMAT_AS(
unsigned char,
unsigned);
3995FMT_FORMAT_AS(
short,
int);
3996FMT_FORMAT_AS(
unsigned short,
unsigned);
3997FMT_FORMAT_AS(
long, detail::long_type);
3998FMT_FORMAT_AS(
unsigned long, detail::ulong_type);
3999FMT_FORMAT_AS(Char*,
const Char*);
4000FMT_FORMAT_AS(std::nullptr_t,
const void*);
4002FMT_FORMAT_AS(
void*,
const void*);
4004template <
typename Char,
typename Traits,
typename Allocator>
4005class formatter<std::basic_string<Char, Traits, Allocator>, Char>
4006 :
public formatter<basic_string_view<Char>, Char> {};
4008template <
typename Char,
size_t N>
4009struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> {};
4018template <
typename T>
auto ptr(T p) ->
const void* {
4019 static_assert(std::is_pointer<T>::value,
"");
4020 return detail::bit_cast<const void*>(p);
4031template <
typename Enum>
4032constexpr auto underlying(Enum e)
noexcept -> underlying_t<Enum> {
4033 return static_cast<underlying_t<Enum>
>(e);
4037template <
typename Enum, FMT_ENABLE_IF(std::is_enum<Enum>::value)>
4038constexpr auto format_as(Enum e)
noexcept -> underlying_t<Enum> {
4039 return static_cast<underlying_t<Enum>
>(e);
4049 explicit bytes(string_view data) : data_(data) {}
4057 template <
typename ParseContext>
4058 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
const char* {
4059 return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
4060 detail::type::string_type);
4063 template <
typename FormatContext>
4064 auto format(
bytes b, FormatContext& ctx)
const ->
decltype(ctx.out()) {
4065 auto specs = specs_;
4066 detail::handle_dynamic_spec<detail::width_checker>(specs.width,
4067 specs.width_ref, ctx);
4068 detail::handle_dynamic_spec<detail::precision_checker>(
4069 specs.precision, specs.precision_ref, ctx);
4070 return detail::write_bytes<char>(ctx.out(), b.data_, specs);
4097 template <
typename ParseContext>
4098 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
const char* {
4099 return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
4100 detail::type::int_type);
4103 template <
typename FormatContext>
4105 ->
decltype(ctx.out()) {
4106 auto specs = specs_;
4107 detail::handle_dynamic_spec<detail::width_checker>(specs.width,
4108 specs.width_ref, ctx);
4109 detail::handle_dynamic_spec<detail::precision_checker>(
4110 specs.precision, specs.precision_ref, ctx);
4111 auto arg = detail::make_write_int_arg(t.value, specs.sign);
4112 return detail::write_int(
4113 ctx.out(),
static_cast<detail::uint64_or_128_t<T>
>(arg.abs_value),
4123template <
typename T,
typename Char>
4125 template <
typename ParseContext>
4126 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
decltype(ctx.begin()) {
4129 template <
typename FormatContext>
4131 ->
decltype(ctx.out()) {
4132 return view.fmt->format(*view.value, ctx);
4136template <
typename T,
typename Char =
char>
struct nested_formatter {
4144 constexpr nested_formatter() : width_(0), align_(align_t::none) {}
4147 ->
decltype(ctx.
begin()) {
4149 auto it = parse_format_specs(ctx.
begin(), ctx.
end(), specs, ctx,
4150 detail::type::none_type);
4151 width_ = specs.width;
4153 align_ = specs.align;
4155 return formatter_.parse(ctx);
4158 template <
typename FormatContext,
typename F>
4159 auto write_padded(FormatContext& ctx, F write)
const ->
decltype(ctx.out()) {
4160 if (width_ == 0)
return write(ctx.out());
4164 specs.width = width_;
4166 specs.align = align_;
4167 return detail::write<Char>(
4183template <
typename T, FMT_ENABLE_IF(!std::is_
integral<T>::value &&
4184 !detail::has_format_as<T>::value)>
4185inline auto to_string(
const T& value) -> std::string {
4186 auto buffer = memory_buffer();
4187 detail::write<char>(appender(buffer), value);
4188 return {buffer.
data(), buffer.
size()};
4191template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
4192FMT_NODISCARD
inline auto to_string(T value) -> std::string {
4195 constexpr int max_size = detail::digits10<T>() + 2;
4196 char buffer[max_size > 5 ?
static_cast<unsigned>(max_size) : 5];
4197 char* begin = buffer;
4198 return std::string(begin, detail::write<char>(begin, value));
4201template <
typename Char,
size_t SIZE>
4203 -> std::basic_string<Char> {
4204 auto size = buf.size();
4205 detail::assume(size < std::basic_string<Char>().max_size());
4206 return std::basic_string<Char>(buf.data(), size);
4209template <
typename T, FMT_ENABLE_IF(!std::is_
integral<T>::value &&
4210 detail::has_format_as<T>::value)>
4211inline auto to_string(
const T& value) -> std::string {
4212 return to_string(format_as(value));
4219template <
typename Char>
4220void vformat_to(
buffer<Char>& buf, basic_string_view<Char> fmt,
4221 typename vformat_args<Char>::type args,
locale_ref loc) {
4222 auto out = basic_appender<Char>(buf);
4223 if (fmt.
size() == 2 && equal2(fmt.
data(),
"{}")) {
4224 auto arg = args.get(0);
4225 if (!arg) report_error(
"argument not found");
4230 struct format_handler {
4231 basic_format_parse_context<Char> parse_context;
4232 buffered_context<Char> context;
4234 format_handler(basic_appender<Char> p_out, basic_string_view<Char> str,
4235 basic_format_args<buffered_context<Char>> p_args,
4237 : parse_context(str), context(p_out, p_args, p_loc) {}
4239 void on_text(
const Char* begin,
const Char* end) {
4240 auto text = basic_string_view<Char>(begin, to_unsigned(end - begin));
4241 context.advance_to(write<Char>(context.out(), text));
4244 FMT_CONSTEXPR
auto on_arg_id() ->
int {
4247 FMT_CONSTEXPR
auto on_arg_id(
int id) ->
int {
4251 FMT_CONSTEXPR
auto on_arg_id(basic_string_view<Char>
id) ->
int {
4253 int arg_id = context.arg_id(
id);
4254 if (arg_id < 0) report_error(
"argument not found");
4258 FMT_INLINE
void on_replacement_field(
int id,
const Char*) {
4259 auto arg = get_arg(context,
id);
4260 context.advance_to(arg.visit(default_arg_formatter<Char>{
4261 context.out(), context.args(), context.locale()}));
4264 auto on_format_specs(
int id,
const Char* begin,
const Char* end)
4266 auto arg = get_arg(context,
id);
4268 if (arg.format_custom(begin, parse_context, context))
4269 return parse_context.
begin();
4270 auto specs = detail::dynamic_format_specs<Char>();
4271 begin = parse_format_specs(begin, end, specs, parse_context, arg.type());
4272 detail::handle_dynamic_spec<detail::width_checker>(
4273 specs.width, specs.width_ref, context);
4274 detail::handle_dynamic_spec<detail::precision_checker>(
4275 specs.precision, specs.precision_ref, context);
4276 if (begin == end || *begin !=
'}')
4277 report_error(
"missing '}' in format string");
4278 context.advance_to(arg.visit(
4279 arg_formatter<Char>{context.out(), specs, context.locale()}));
4283 FMT_NORETURN
void on_error(
const char* message) { report_error(message); }
4285 detail::parse_format_string<false>(fmt, format_handler(out, fmt, args, loc));
4290#ifndef FMT_HEADER_ONLY
4291extern template FMT_API
void vformat_to(
buffer<char>&, string_view,
4292 typename vformat_args<>::type,
4294extern template FMT_API
auto thousands_sep_impl<char>(
locale_ref)
4296extern template FMT_API
auto thousands_sep_impl<wchar_t>(
locale_ref)
4298extern template FMT_API
auto decimal_point_impl(
locale_ref) -> char;
4299extern template FMT_API
auto decimal_point_impl(
locale_ref) -> wchar_t;
4304template <
typename T,
typename Char, type TYPE>
4305template <
typename FormatContext>
4306FMT_CONSTEXPR FMT_INLINE
auto native_formatter<T, Char, TYPE>::format(
4307 const T& val, FormatContext& ctx)
const ->
decltype(ctx.out()) {
4308 if (specs_.width_ref.kind == arg_id_kind::none &&
4309 specs_.precision_ref.kind == arg_id_kind::none) {
4310 return write<Char>(ctx.out(), val, specs_, ctx.locale());
4312 auto specs = specs_;
4313 handle_dynamic_spec<width_checker>(specs.width, specs.width_ref, ctx);
4314 handle_dynamic_spec<precision_checker>(specs.precision, specs.precision_ref,
4316 return write<Char>(ctx.out(), val, specs, ctx.locale());
4323template <
typename Char>
4324struct formatter<detail::float128, Char>
4326 detail::type::float_type> {};
4328#if FMT_USE_USER_DEFINED_LITERALS
4329inline namespace literals {
4338# if FMT_USE_NONTYPE_TEMPLATE_ARGS
4339template <detail_exported::fixed_
string Str>
constexpr auto operator""_a() {
4340 using char_t = remove_cvref_t<
decltype(Str.data[0])>;
4341 return detail::udl_arg<char_t,
sizeof(Str.data) /
sizeof(char_t), Str>();
4344constexpr auto operator""_a(
const char* s,
size_t) -> detail::udl_arg<char> {
4351FMT_API
auto vformat(string_view fmt, format_args args) -> std::string;
4362template <
typename... T>
4363FMT_NODISCARD FMT_INLINE
auto format(format_string<T...> fmt, T&&... args)
4365 return vformat(fmt, fmt::make_format_args(args...));
4368template <
typename Locale, FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
4369inline auto vformat(
const Locale& loc, string_view fmt, format_args args)
4371 return detail::vformat(loc, fmt, args);
4374template <
typename Locale,
typename... T,
4375 FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
4376inline auto format(
const Locale& loc, format_string<T...> fmt, T&&... args)
4378 return fmt::vformat(loc, string_view(fmt), fmt::make_format_args(args...));
4381template <
typename OutputIt,
typename Locale,
4383 detail::is_locale<Locale>::value)>
4384auto vformat_to(OutputIt out,
const Locale& loc, string_view fmt,
4385 format_args args) -> OutputIt {
4386 using detail::get_buffer;
4387 auto&& buf = get_buffer<char>(out);
4389 return detail::get_iterator(buf, out);
4392template <
typename OutputIt,
typename Locale,
typename... T,
4394 detail::is_locale<Locale>::value)>
4395FMT_INLINE
auto format_to(OutputIt out,
const Locale& loc,
4396 format_string<T...> fmt, T&&... args) -> OutputIt {
4397 return vformat_to(out, loc, fmt, fmt::make_format_args(args...));
4400template <
typename Locale,
typename... T,
4401 FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
4402FMT_NODISCARD FMT_INLINE
auto formatted_size(
const Locale& loc,
4403 format_string<T...> fmt,
4404 T&&... args) ->
size_t {
4406 detail::vformat_to<char>(buf, fmt, fmt::make_format_args(args...),
4415#ifdef FMT_HEADER_ONLY
4416# define FMT_FUNC inline
4417# include "format-inl.h"
4423#ifdef FMT_REMOVE_TRANSITIVE_INCLUDES
4424# undef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES
FMT_CONSTEXPR auto next_arg_id() -> int
Definition base.h:784
constexpr auto end() const noexcept -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition base.h:775
FMT_CONSTEXPR void check_arg_id(int id)
Definition base.h:796
FMT_CONSTEXPR void advance_to(iterator it)
Advances the begin iterator to it.
Definition base.h:778
constexpr auto begin() const noexcept -> iterator
Definition base.h:770
FMT_CONSTEXPR20 void resize(size_t count)
Definition format.h:924
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:912
void reserve(size_t new_capacity)
Increases the buffer capacity to new_capacity.
Definition format.h:927
FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer &&other) noexcept
Definition format.h:906
constexpr auto size() const noexcept -> size_t
Returns the string size.
Definition base.h:555
constexpr auto data() const noexcept -> const Char *
Returns a pointer to the string data.
Definition base.h:552
FMT_CONSTEXPR void set(T *buf_data, size_t buf_capacity) noexcept
Sets the buffer data and capacity.
Definition base.h:875
void clear()
Clears this buffer.
Definition base.h:904
constexpr auto size() const noexcept -> size_t
Returns the size of this buffer.
Definition base.h:894
constexpr auto capacity() const noexcept -> size_t
Returns the capacity of this buffer.
Definition base.h:897
FMT_CONSTEXPR auto data() noexcept -> T *
Returns a pointer to the buffer data (not null-terminated).
Definition base.h:900
An error reported from a formatting function.
Definition format.h:961