36#ifndef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES
37# define _LIBCPP_REMOVE_TRANSITIVE_INCLUDES
38# define FMT_REMOVE_TRANSITIVE_INCLUDES
45# include <initializer_list>
47# if defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI)
53# include <system_error>
59#if FMT_HAS_INCLUDE(<bit>) && FMT_CPLUSPLUS > 201703L && \
60 !defined(FMT_IMPORT_STD)
65#if FMT_HAS_INCLUDE(<string_view>) && \
66 (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION))
67# ifndef FMT_IMPORT_STD
68# include <string_view>
70# define FMT_USE_STRING_VIEW
73#if defined __cpp_inline_variables && __cpp_inline_variables >= 201606L
74# define FMT_INLINE_VARIABLE inline
76# define FMT_INLINE_VARIABLE
79#ifndef FMT_NO_UNIQUE_ADDRESS
80# if FMT_CPLUSPLUS >= 202002L
81# if FMT_HAS_CPP_ATTRIBUTE(no_unique_address)
82# define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]]
84# elif (FMT_MSC_VERSION >= 1929) && !FMT_CLANG_VERSION
85# define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
89#ifndef FMT_NO_UNIQUE_ADDRESS
90# define FMT_NO_UNIQUE_ADDRESS
94#if defined(FMT_LIB_EXPORT) || defined(FMT_SHARED)
95# define FMT_SO_VISIBILITY(value) FMT_VISIBILITY(value)
97# define FMT_SO_VISIBILITY(value)
101# define FMT_HAS_BUILTIN(x) __has_builtin(x)
103# define FMT_HAS_BUILTIN(x) 0
106#if FMT_GCC_VERSION || FMT_CLANG_VERSION
107# define FMT_NOINLINE __attribute__((noinline))
114# if FMT_MSC_VERSION || defined(__NVCC__)
117template <
typename Exception>
inline void do_throw(
const Exception& x) {
120 volatile bool b =
true;
125# define FMT_THROW(x) detail::do_throw(x)
127# define FMT_THROW(x) throw x
130# define FMT_THROW(x) \
131 ::fmt::detail::assert_fail(__FILE__, __LINE__, (x).what())
135#ifndef FMT_MAYBE_UNUSED
136# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused)
137# define FMT_MAYBE_UNUSED [[maybe_unused]]
139# define FMT_MAYBE_UNUSED
143#ifndef FMT_USE_USER_DEFINED_LITERALS
148# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 409 || \
149 FMT_MSC_VERSION >= 1900) && \
150 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 480)
151# define FMT_USE_USER_DEFINED_LITERALS 1
153# define FMT_USE_USER_DEFINED_LITERALS 0
161#if !defined(FMT_REDUCE_INT_INSTANTIATIONS)
162# define FMT_REDUCE_INT_INSTANTIATIONS 0
168# if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION
169# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
171# if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION
172# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
179# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION || \
180 defined(__NVCOMPILER)
181# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n)
183# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || \
184 FMT_ICC_VERSION || defined(__NVCOMPILER)
185# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n)
196#if FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) && \
197 !defined(FMT_BUILTIN_CTZLL)
201# if !defined(__clang__)
202# pragma intrinsic(_BitScanForward)
203# pragma intrinsic(_BitScanReverse)
205# pragma intrinsic(_BitScanForward64)
206# pragma intrinsic(_BitScanReverse64)
210inline auto clz(uint32_t x) ->
int {
212 _BitScanReverse(&r, x);
213 FMT_ASSERT(x != 0,
"");
217 FMT_MSC_WARNING(suppress : 6102)
218 return 31 ^ static_cast<int>(r);
220# define FMT_BUILTIN_CLZ(n) detail::clz(n)
222inline auto clzll(uint64_t x) ->
int {
225 _BitScanReverse64(&r, x);
228 if (_BitScanReverse(&r,
static_cast<uint32_t>(x >> 32)))
229 return 63 ^
static_cast<int>(r + 32);
231 _BitScanReverse(&r,
static_cast<uint32_t>(x));
233 FMT_ASSERT(x != 0,
"");
234 FMT_MSC_WARNING(suppress : 6102)
235 return 63 ^ static_cast<int>(r);
237# define FMT_BUILTIN_CLZLL(n) detail::clzll(n)
239inline auto ctz(uint32_t x) ->
int {
241 _BitScanForward(&r, x);
242 FMT_ASSERT(x != 0,
"");
243 FMT_MSC_WARNING(suppress : 6102)
244 return static_cast<int>(r);
246# define FMT_BUILTIN_CTZ(n) detail::ctz(n)
248inline auto ctzll(uint64_t x) ->
int {
250 FMT_ASSERT(x != 0,
"");
251 FMT_MSC_WARNING(suppress : 6102)
253 _BitScanForward64(&r, x);
256 if (_BitScanForward(&r,
static_cast<uint32_t>(x)))
return static_cast<int>(r);
258 _BitScanForward(&r,
static_cast<uint32_t>(x >> 32));
261 return static_cast<int>(r);
263# define FMT_BUILTIN_CTZLL(n) detail::ctzll(n)
270template <
typename Char,
typename Traits,
typename Allocator>
276FMT_CONSTEXPR
inline void abort_fuzzing_if(
bool condition) {
277 ignore_unused(condition);
279 if (condition)
throw std::runtime_error(
"fuzzing limit reached");
283#if defined(FMT_USE_STRING_VIEW)
284template <
typename Char>
using std_string_view = std::basic_string_view<Char>;
290template <
typename To,
typename From, FMT_ENABLE_IF(sizeof(To) == sizeof(From))>
291FMT_CONSTEXPR20
auto bit_cast(
const From& from) -> To {
292#ifdef __cpp_lib_bit_cast
293 if (is_constant_evaluated())
return std::bit_cast<To>(from);
297 std::memcpy(
static_cast<void*
>(&to), &from,
sizeof(to));
301inline auto is_big_endian() ->
bool {
304#elif defined(__BIG_ENDIAN__)
306#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
307 return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;
310 char data[
sizeof(int)];
312 return bit_cast<bytes>(1).data[0] == 0;
324 constexpr auto high()
const noexcept -> uint64_t {
return hi_; }
325 constexpr auto low()
const noexcept -> uint64_t {
return lo_; }
327 template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
328 constexpr explicit operator T()
const {
329 return static_cast<T
>(lo_);
334 return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_;
338 return !(lhs == rhs);
342 return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_;
347 return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_};
352 return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_};
356 return {~n.hi_, ~n.lo_};
366 FMT_ASSERT(lhs.hi_ == 0,
"");
367 uint64_t hi = (lhs.lo_ >> 32) * rhs;
368 uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs;
369 uint64_t new_lo = (hi << 32) + lo;
370 return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo};
374 return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs};
377 if (shift == 64)
return {0, hi_};
379 return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)};
382 if (shift == 64)
return {lo_, 0};
384 return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)};
387 return *
this = *
this >> shift;
390 uint64_t new_lo = lo_ + n.lo_;
391 uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0);
392 FMT_ASSERT(new_hi >= hi_,
"");
402 if (is_constant_evaluated()) {
404 hi_ += (lo_ < n ? 1 : 0);
407#if FMT_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__)
408 unsigned long long carry;
409 lo_ = __builtin_addcll(lo_, n, 0, &carry);
411#elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__)
412 unsigned long long result;
413 auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result);
416#elif defined(_MSC_VER) && defined(_M_X64)
417 auto carry = _addcarry_u64(0, lo_, n, &lo_);
418 _addcarry_u64(carry, hi_, 0, &hi_);
421 hi_ += (lo_ < n ? 1 : 0);
427using uint128_t = conditional_t<FMT_USE_INT128, uint128_opt, uint128_fallback>;
430using uintptr_t = ::uintptr_t;
432using uintptr_t = uint128_t;
437template <
typename T>
constexpr auto max_value() -> T {
438 return (std::numeric_limits<T>::max)();
440template <
typename T>
constexpr auto num_bits() ->
int {
441 return std::numeric_limits<T>::digits;
444template <>
constexpr auto num_bits<int128_opt>() ->
int {
return 128; }
445template <>
constexpr auto num_bits<uint128_opt>() ->
int {
return 128; }
446template <>
constexpr auto num_bits<uint128_fallback>() ->
int {
return 128; }
450template <
typename To,
typename From, FMT_ENABLE_IF(sizeof(To) >
sizeof(From))>
451inline auto bit_cast(
const From& from) -> To {
452 constexpr auto size =
static_cast<int>(
sizeof(From) /
sizeof(
unsigned));
454 unsigned value[
static_cast<unsigned>(size)];
455 } data = bit_cast<data_t>(from);
457 if (const_check(is_big_endian())) {
458 for (
int i = 0; i < size; ++i)
459 result = (result << num_bits<unsigned>()) | data.value[i];
461 for (
int i = size - 1; i >= 0; --i)
462 result = (result << num_bits<unsigned>()) | data.value[i];
467template <
typename UInt>
468FMT_CONSTEXPR20
inline auto countl_zero_fallback(UInt n) ->
int {
470 constexpr UInt msb_mask =
static_cast<UInt
>(1) << (num_bits<UInt>() - 1);
471 for (; (n & msb_mask) == 0; n <<= 1) lz++;
475FMT_CONSTEXPR20
inline auto countl_zero(uint32_t n) ->
int {
476#ifdef FMT_BUILTIN_CLZ
477 if (!is_constant_evaluated())
return FMT_BUILTIN_CLZ(n);
479 return countl_zero_fallback(n);
482FMT_CONSTEXPR20
inline auto countl_zero(uint64_t n) ->
int {
483#ifdef FMT_BUILTIN_CLZLL
484 if (!is_constant_evaluated())
return FMT_BUILTIN_CLZLL(n);
486 return countl_zero_fallback(n);
489FMT_INLINE
void assume(
bool condition) {
491#if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION
492 __builtin_assume(condition);
494 if (!condition) __builtin_unreachable();
500using iterator_t =
decltype(std::begin(std::declval<T&>()));
501template <
typename T>
using sentinel_t =
decltype(std::end(std::declval<T&>()));
504template <
typename Char>
505inline auto get_data(std::basic_string<Char>& s) -> Char* {
508template <
typename Container>
509inline auto get_data(Container& c) ->
typename Container::value_type* {
515template <
typename OutputIt,
516 FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value&&
518#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION
519__attribute__((no_sanitize(
"undefined")))
522reserve(OutputIt it,
size_t n) ->
typename OutputIt::value_type* {
523 auto& c = get_container(it);
524 size_t size = c.size();
526 return get_data(c) + size;
531 buffer<T>& buf = get_container(it);
532 buf.try_reserve(buf.size() + n);
536template <
typename Iterator>
537constexpr auto reserve(Iterator& it,
size_t) -> Iterator& {
541template <
typename OutputIt>
542using reserve_iterator =
543 remove_reference_t<decltype(reserve(std::declval<OutputIt&>(), 0))>;
545template <
typename T,
typename OutputIt>
546constexpr auto to_pointer(OutputIt,
size_t) -> T* {
550 buffer<T>& buf = get_container(it);
551 auto size = buf.size();
552 if (buf.capacity() < size + n)
return nullptr;
553 buf.try_resize(size + n);
554 return buf.data() + size;
557template <
typename OutputIt,
558 FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value&&
560inline auto base_iterator(OutputIt it,
561 typename OutputIt::container_type::value_type*)
566template <
typename Iterator>
567constexpr auto base_iterator(Iterator, Iterator it) -> Iterator {
573template <
typename OutputIt,
typename Size,
typename T>
574FMT_CONSTEXPR
auto fill_n(OutputIt out, Size count,
const T& value)
576 for (Size i = 0; i < count; ++i) *out++ = value;
579template <
typename T,
typename Size>
580FMT_CONSTEXPR20
auto fill_n(T* out, Size count,
char value) -> T* {
581 if (is_constant_evaluated()) {
582 return fill_n<T*, Size, T>(out, count, value);
584 std::memset(out, value, to_unsigned(count));
588template <
typename OutChar,
typename InputIt,
typename OutputIt>
589FMT_CONSTEXPR FMT_NOINLINE
auto copy_noinline(InputIt begin, InputIt end,
590 OutputIt out) -> OutputIt {
591 return copy<OutChar>(begin, end, out);
611FMT_CONSTEXPR
inline auto utf8_decode(
const char* s, uint32_t* c,
int* e)
613 constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
614 constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
615 constexpr const int shiftc[] = {0, 18, 12, 6, 0};
616 constexpr const int shifte[] = {0, 6, 4, 2, 0};
618 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"
619 [
static_cast<unsigned char>(*s) >> 3];
623 const char* next = s + len + !len;
625 using uchar =
unsigned char;
629 *c =
uint32_t(uchar(s[0]) & masks[len]) << 18;
630 *c |=
uint32_t(uchar(s[1]) & 0x3f) << 12;
631 *c |=
uint32_t(uchar(s[2]) & 0x3f) << 6;
632 *c |=
uint32_t(uchar(s[3]) & 0x3f) << 0;
636 *e = (*c < mins[len]) << 6;
637 *e |= ((*c >> 11) == 0x1b) << 7;
638 *e |= (*c > 0x10FFFF) << 8;
639 *e |= (uchar(s[1]) & 0xc0) >> 2;
640 *e |= (uchar(s[2]) & 0xc0) >> 4;
641 *e |= uchar(s[3]) >> 6;
648constexpr FMT_INLINE_VARIABLE
uint32_t invalid_code_point = ~uint32_t();
653FMT_CONSTEXPR
void for_each_codepoint(
string_view s, F f) {
654 auto decode = [f](
const char* buf_ptr,
const char* ptr) {
657 auto end = utf8_decode(buf_ptr, &cp, &error);
658 bool result = f(error ? invalid_code_point : cp,
659 string_view(ptr, error ? 1 : to_unsigned(end - buf_ptr)));
660 return result ? (error ? buf_ptr + 1 : end) : nullptr;
663 const size_t block_size = 4;
664 if (s.size() >= block_size) {
665 for (
auto end = p + s.size() - block_size + 1; p < end;) {
670 if (
auto num_chars_left = s.data() + s.size() - p) {
671 char buf[2 * block_size - 1] = {};
672 copy<char>(p, p + num_chars_left, buf);
673 const char* buf_ptr = buf;
675 auto end = decode(buf_ptr, p);
679 }
while (buf_ptr - buf < num_chars_left);
683template <
typename Char>
689FMT_CONSTEXPR
inline auto compute_width(
string_view s) ->
size_t {
690 size_t num_code_points = 0;
692 struct count_code_points {
694 FMT_CONSTEXPR
auto operator()(uint32_t cp,
string_view)
const ->
bool {
695 *count += detail::to_unsigned(
702 (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) ||
703 (cp >= 0xac00 && cp <= 0xd7a3) ||
704 (cp >= 0xf900 && cp <= 0xfaff) ||
705 (cp >= 0xfe10 && cp <= 0xfe19) ||
706 (cp >= 0xfe30 && cp <= 0xfe6f) ||
707 (cp >= 0xff00 && cp <= 0xff60) ||
708 (cp >= 0xffe0 && cp <= 0xffe6) ||
709 (cp >= 0x20000 && cp <= 0x2fffd) ||
710 (cp >= 0x30000 && cp <= 0x3fffd) ||
712 (cp >= 0x1f300 && cp <= 0x1f64f) ||
714 (cp >= 0x1f900 && cp <= 0x1f9ff))));
719 for_each_codepoint(s, count_code_points{&num_code_points});
720 return num_code_points;
723template <
typename Char>
725 size_t size = s.size();
726 return n < size ? n : size;
730inline auto code_point_index(
string_view s,
size_t n) ->
size_t {
731 size_t result = s.size();
732 const char* begin = s.begin();
733 for_each_codepoint(s, [begin, &n, &result](uint32_t,
string_view sv) {
738 result = to_unsigned(sv.begin() - begin);
750 std::integral_constant<bool, std::numeric_limits<T>::is_signed ||
751 std::is_same<T, int128_opt>::value>;
755 bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value &&
756 !std::is_same<T, char>::value &&
757 !std::is_same<T, wchar_t>::value>;
760# define FMT_USE_FLOAT 1
762#ifndef FMT_USE_DOUBLE
763# define FMT_USE_DOUBLE 1
765#ifndef FMT_USE_LONG_DOUBLE
766# define FMT_USE_LONG_DOUBLE 1
769#if defined(FMT_USE_FLOAT128)
771#elif FMT_CLANG_VERSION && FMT_HAS_INCLUDE(<quadmath.h>)
772# define FMT_USE_FLOAT128 1
773#elif FMT_GCC_VERSION && defined(_GLIBCXX_USE_FLOAT128) && \
774 !defined(__STRICT_ANSI__)
775# define FMT_USE_FLOAT128 1
777# define FMT_USE_FLOAT128 0
780using float128 = __float128;
782using float128 = void;
785template <
typename T>
using is_float128 = std::is_same<T, float128>;
788using is_floating_point =
789 bool_constant<std::is_floating_point<T>::value || is_float128<T>::value>;
791template <typename T, bool = std::is_floating_point<T>::value>
792struct is_fast_float : bool_constant<std::numeric_limits<T>::is_iec559 &&
793 sizeof(T) <= sizeof(double)> {};
794template <typename T> struct is_fast_float<T, false> : std::false_type {};
797using is_double_double = bool_constant<std::numeric_limits<T>::digits == 106>;
799#ifndef FMT_USE_FULL_CACHE_DRAGONBOX
800# define FMT_USE_FULL_CACHE_DRAGONBOX 0
803template <typename T, typename Enable = void>
804struct is_locale : std::false_type {};
806struct is_locale<T, void_t<decltype(T::classic())>> : std::true_type {};
813enum { inline_buffer_size = 500 };
836template <typename T, size_t SIZE = inline_buffer_size,
837 typename Allocator = std::allocator<T>>
838class basic_memory_buffer : public detail::buffer<T> {
843 FMT_NO_UNIQUE_ADDRESS Allocator alloc_;
846 FMT_CONSTEXPR20 void deallocate() {
847 T* data = this->data();
848 if (data != store_) alloc_.deallocate(data, this->capacity());
851 static FMT_CONSTEXPR20 void grow(detail::buffer<T>& buf, size_t size) {
852 detail::abort_fuzzing_if(size > 5000);
854 const size_t max_size =
855 std::allocator_traits<Allocator>::max_size(self.alloc_);
856 size_t old_capacity = buf.capacity();
857 size_t new_capacity = old_capacity + old_capacity / 2;
858 if (size > new_capacity)
860 else if (new_capacity > max_size)
861 new_capacity = size > max_size ? size : max_size;
862 T* old_data = buf.data();
863 T* new_data = self.alloc_.allocate(new_capacity);
865 detail::assume(buf.size() <= new_capacity);
867 memcpy(new_data, old_data, buf.size() *
sizeof(T));
868 self.set(new_data, new_capacity);
872 if (old_data != self.store_) self.alloc_.deallocate(old_data, old_capacity);
876 using value_type = T;
877 using const_reference =
const T&;
880 const Allocator& alloc = Allocator())
881 : detail::buffer<T>(grow), alloc_(alloc) {
882 this->set(store_, SIZE);
883 if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T());
890 alloc_ = std::move(other.alloc_);
891 T* data = other.
data();
892 size_t size = other.
size(), capacity = other.
capacity();
893 if (data == other.store_) {
894 this->set(store_, capacity);
895 detail::copy<T>(other.store_, other.store_ + size, store_);
897 this->set(data, capacity);
900 other.
set(other.store_, 0);
924 FMT_ASSERT(
this != &other,
"");
931 auto get_allocator() const -> Allocator {
return alloc_; }
937 FMT_CONSTEXPR20
void resize(
size_t count) { this->try_resize(count); }
940 void reserve(
size_t new_capacity) { this->try_reserve(new_capacity); }
943 template <
typename ContiguousRange>
944 void append(
const ContiguousRange& range) {
945 append(range.data(), range.data() + range.size());
951template <
typename T,
size_t SIZE,
typename Allocator>
957FMT_API
auto write_console(
int fd,
string_view text) -> bool;
965# pragma clang diagnostic ignored "-Wweak-vtables"
969class FMT_SO_VISIBILITY(
"default") format_error :
public std::runtime_error {
971 using std::runtime_error::runtime_error;
975#if FMT_USE_NONTYPE_TEMPLATE_ARGS
976template <
typename Char,
size_t N>
struct fixed_string {
977 constexpr fixed_string(
const Char (&str)[N]) {
978 detail::copy<Char, const Char*, Char*>(
static_cast<const Char*
>(str),
986template <
typename Char,
size_t N>
987constexpr auto compile_string_to_view(
const Char (&s)[N])
991 return {s, N - (std::char_traits<Char>::to_int_type(s[N - 1]) == 0 ? 1 : 0)};
993template <
typename Char>
1010 using char_type = Char;
1011 using iterator = OutputIt;
1018 : out_(out), args_(ctx_args), loc_(loc) {}
1024 return args_.
get(
id);
1027 return args_.
get(name);
1030 return args_.get_id(name);
1036 FMT_CONSTEXPR
auto out() -> iterator {
return out_; }
1038 void advance_to(iterator it) {
1050 template <
typename T, FMT_ENABLE_IF(!detail::is_
float128<T>::value)>
1051 loc_value(T value) : value_(detail::make_arg<format_context>(value)) {}
1053 template <
typename T, FMT_ENABLE_IF(detail::is_
float128<T>::value)>
1056 template <
typename Visitor>
auto visit(Visitor&& vis) ->
decltype(vis(0)) {
1057 return value_.
visit(vis);
1065 std::string separator_;
1066 std::string grouping_;
1067 std::string decimal_point_;
1074 static FMT_API
typename Locale::id id;
1078 std::initializer_list<unsigned char> g = {3},
1079 std::string decimal_point =
".")
1080 : separator_(sep.data(), sep.size()),
1081 grouping_(g.begin(), g.end()),
1082 decimal_point_(decimal_point) {}
1086 return do_put(out, val, specs);
1094template <
typename T, FMT_ENABLE_IF(is_
signed<T>::value)>
1095constexpr auto is_negative(T value) ->
bool {
1098template <
typename T, FMT_ENABLE_IF(!is_
signed<T>::value)>
1099constexpr auto is_negative(T) ->
bool {
1103template <
typename T>
1104FMT_CONSTEXPR
auto is_supported_floating_point(T) ->
bool {
1105 if (std::is_same<T, float>())
return FMT_USE_FLOAT;
1106 if (std::is_same<T, double>())
return FMT_USE_DOUBLE;
1107 if (std::is_same<T, long double>())
return FMT_USE_LONG_DOUBLE;
1113template <
typename T>
1114using uint32_or_64_or_128_t =
1115 conditional_t<num_bits<T>() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS,
1117 conditional_t<num_bits<T>() <= 64,
uint64_t, uint128_t>>;
1118template <
typename T>
1119using uint64_or_128_t = conditional_t<num_bits<T>() <= 64,
uint64_t, uint128_t>;
1121#define FMT_POWERS_OF_10(factor) \
1122 factor * 10, (factor) * 100, (factor) * 1000, (factor) * 10000, \
1123 (factor) * 100000, (factor) * 1000000, (factor) * 10000000, \
1124 (factor) * 100000000, (factor) * 1000000000
1127constexpr auto digits2(
size_t value) ->
const char* {
1129 return &
"0001020304050607080910111213141516171819"
1130 "2021222324252627282930313233343536373839"
1131 "4041424344454647484950515253545556575859"
1132 "6061626364656667686970717273747576777879"
1133 "8081828384858687888990919293949596979899"[value * 2];
1137template <
typename Char,
typename Sign>
constexpr auto sign(Sign s) -> Char {
1138#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604
1139 static_assert(std::is_same<Sign, sign_t>::value,
"");
1141 return static_cast<Char
>(
"\0-+ "[s]);
1144template <
typename T> FMT_CONSTEXPR
auto count_digits_fallback(T n) ->
int {
1150 if (n < 10)
return count;
1151 if (n < 100)
return count + 1;
1152 if (n < 1000)
return count + 2;
1153 if (n < 10000)
return count + 3;
1159FMT_CONSTEXPR
inline auto count_digits(uint128_opt n) ->
int {
1160 return count_digits_fallback(n);
1164#ifdef FMT_BUILTIN_CLZLL
1167inline auto do_count_digits(uint64_t n) ->
int {
1172 static constexpr uint8_t bsr2log10[] = {
1173 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
1174 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
1175 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
1176 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20};
1177 auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63];
1178 static constexpr const uint64_t zero_or_powers_of_10[] = {
1179 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL),
1180 10000000000000000000ULL};
1181 return t - (n < zero_or_powers_of_10[t]);
1187FMT_CONSTEXPR20
inline auto count_digits(uint64_t n) ->
int {
1188#ifdef FMT_BUILTIN_CLZLL
1189 if (!is_constant_evaluated())
return do_count_digits(n);
1191 return count_digits_fallback(n);
1195template <
int BITS,
typename UInt>
1196FMT_CONSTEXPR
auto count_digits(UInt n) ->
int {
1197#ifdef FMT_BUILTIN_CLZ
1198 if (!is_constant_evaluated() && num_bits<UInt>() == 32)
1199 return (FMT_BUILTIN_CLZ(
static_cast<uint32_t>(n) | 1) ^ 31) / BITS + 1;
1206 }
while ((m >>= BITS) != 0);
1211#ifdef FMT_BUILTIN_CLZ
1214FMT_INLINE
auto do_count_digits(uint32_t n) ->
int {
1217# define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T)
1218 static constexpr uint64_t table[] = {
1219 FMT_INC(0), FMT_INC(0), FMT_INC(0),
1220 FMT_INC(10), FMT_INC(10), FMT_INC(10),
1221 FMT_INC(100), FMT_INC(100), FMT_INC(100),
1222 FMT_INC(1000), FMT_INC(1000), FMT_INC(1000),
1223 FMT_INC(10000), FMT_INC(10000), FMT_INC(10000),
1224 FMT_INC(100000), FMT_INC(100000), FMT_INC(100000),
1225 FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000),
1226 FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000),
1227 FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000),
1228 FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000),
1229 FMT_INC(1000000000), FMT_INC(1000000000)
1231 auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31];
1232 return static_cast<int>((n + inc) >> 32);
1237FMT_CONSTEXPR20
inline auto count_digits(uint32_t n) ->
int {
1238#ifdef FMT_BUILTIN_CLZ
1239 if (!is_constant_evaluated()) {
1240 return do_count_digits(n);
1243 return count_digits_fallback(n);
1246template <
typename Int>
constexpr auto digits10() noexcept ->
int {
1247 return std::numeric_limits<Int>::digits10;
1249template <>
constexpr auto digits10<int128_opt>() noexcept ->
int {
return 38; }
1250template <>
constexpr auto digits10<uint128_t>() noexcept ->
int {
return 38; }
1253 std::string grouping;
1257template <
typename Char>
1259template <
typename Char>
1261 auto result = thousands_sep_impl<char>(loc);
1262 return {result.grouping, Char(result.thousands_sep)};
1265inline auto thousands_sep(locale_ref loc) -> thousands_sep_result<wchar_t> {
1266 return thousands_sep_impl<wchar_t>(loc);
1269template <
typename Char>
1270FMT_API
auto decimal_point_impl(locale_ref loc) -> Char;
1271template <
typename Char>
inline auto decimal_point(locale_ref loc) -> Char {
1272 return Char(decimal_point_impl<char>(loc));
1274template <>
inline auto decimal_point(locale_ref loc) ->
wchar_t {
1275 return decimal_point_impl<wchar_t>(loc);
1279template <
typename Char>
auto equal2(
const Char* lhs,
const char* rhs) ->
bool {
1280 return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]);
1282inline auto equal2(
const char* lhs,
const char* rhs) ->
bool {
1283 return memcmp(lhs, rhs, 2) == 0;
1287template <
typename Char>
1288FMT_CONSTEXPR20 FMT_INLINE
void copy2(Char* dst,
const char* src) {
1289 if (!is_constant_evaluated() &&
sizeof(Char) ==
sizeof(
char)) {
1290 memcpy(dst, src, 2);
1293 *dst++ =
static_cast<Char
>(*src++);
1294 *dst =
static_cast<Char
>(*src);
1305template <
typename Char,
typename UInt>
1306FMT_CONSTEXPR20
auto format_decimal(Char* out, UInt
value,
int size)
1308 FMT_ASSERT(size >= count_digits(
value),
"invalid digit count");
1311 while (
value >= 100) {
1316 copy2(out, digits2(
static_cast<size_t>(
value % 100)));
1320 *--out =
static_cast<Char
>(
'0' + value);
1324 copy2(out, digits2(
static_cast<size_t>(value)));
1328template <
typename Char,
typename UInt,
typename Iterator,
1329 FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<Iterator>>::value)>
1330FMT_CONSTEXPR
inline auto format_decimal(Iterator out, UInt value,
int size)
1331 -> format_decimal_result<Iterator> {
1333 Char buffer[digits10<UInt>() + 1] = {};
1334 auto end = format_decimal(buffer, value, size).end;
1335 return {out, detail::copy_noinline<Char>(buffer, end, out)};
1338template <
unsigned BASE_BITS,
typename Char,
typename UInt>
1339FMT_CONSTEXPR
auto format_uint(Char* buffer, UInt value,
int num_digits,
1340 bool upper =
false) -> Char* {
1341 buffer += num_digits;
1344 const char* digits = upper ?
"0123456789ABCDEF" :
"0123456789abcdef";
1345 unsigned digit =
static_cast<unsigned>(value & ((1 << BASE_BITS) - 1));
1346 *--buffer =
static_cast<Char
>(BASE_BITS < 4 ? static_cast<char>(
'0' + digit)
1348 }
while ((value >>= BASE_BITS) != 0);
1352template <
unsigned BASE_BITS,
typename Char,
typename It,
typename UInt>
1353FMT_CONSTEXPR
inline auto format_uint(It out, UInt value,
int num_digits,
1354 bool upper =
false) -> It {
1355 if (
auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
1356 format_uint<BASE_BITS>(ptr, value, num_digits, upper);
1360 char buffer[num_bits<UInt>() / BASE_BITS + 1] = {};
1361 format_uint<BASE_BITS>(buffer, value, num_digits, upper);
1362 return detail::copy_noinline<Char>(buffer, buffer + num_digits, out);
1373 auto size()
const ->
size_t {
return buffer_.
size() - 1; }
1374 auto c_str()
const ->
const wchar_t* {
return &buffer_[0]; }
1375 auto str()
const -> std::wstring {
return {&buffer_[0], size()}; }
1378enum class to_utf8_error_policy { abort, replace };
1381template <
typename WChar,
typename Buffer = memory_buffer>
class to_utf8 {
1388 to_utf8_error_policy policy = to_utf8_error_policy::abort) {
1389 static_assert(
sizeof(WChar) == 2 ||
sizeof(WChar) == 4,
1390 "Expect utf16 or utf32");
1391 if (!convert(s, policy))
1392 FMT_THROW(std::runtime_error(
sizeof(WChar) == 2 ?
"invalid utf16"
1393 :
"invalid utf32"));
1396 auto size()
const ->
size_t {
return buffer_.size() - 1; }
1397 auto c_str()
const ->
const char* {
return &buffer_[0]; }
1398 auto str()
const -> std::string {
return std::string(&buffer_[0], size()); }
1404 to_utf8_error_policy policy = to_utf8_error_policy::abort)
1406 if (!convert(buffer_, s, policy))
return false;
1407 buffer_.push_back(0);
1411 to_utf8_error_policy policy = to_utf8_error_policy::abort)
1413 for (
auto p = s.begin(); p != s.end(); ++p) {
1414 uint32_t c =
static_cast<uint32_t
>(*p);
1415 if (
sizeof(WChar) == 2 && c >= 0xd800 && c <= 0xdfff) {
1418 if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) {
1419 if (policy == to_utf8_error_policy::abort)
return false;
1423 c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;
1425 }
else if (c < 0x80) {
1426 buf.push_back(
static_cast<char>(c));
1427 }
else if (c < 0x800) {
1428 buf.push_back(
static_cast<char>(0xc0 | (c >> 6)));
1429 buf.push_back(
static_cast<char>(0x80 | (c & 0x3f)));
1430 }
else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
1431 buf.push_back(
static_cast<char>(0xe0 | (c >> 12)));
1432 buf.push_back(
static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
1433 buf.push_back(
static_cast<char>(0x80 | (c & 0x3f)));
1434 }
else if (c >= 0x10000 && c <= 0x10ffff) {
1435 buf.push_back(
static_cast<char>(0xf0 | (c >> 18)));
1436 buf.push_back(
static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
1437 buf.push_back(
static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
1438 buf.push_back(
static_cast<char>(0x80 | (c & 0x3f)));
1450 auto p =
static_cast<uint128_opt
>(x) *
static_cast<uint128_opt
>(y);
1451 return {
static_cast<uint64_t
>(p >> 64),
static_cast<uint64_t
>(p)};
1452#elif defined(_MSC_VER) && defined(_M_X64)
1453 auto hi = uint64_t();
1454 auto lo = _umul128(x, y, &hi);
1471 return {ac + (
intermediate >> 32) + (ad >> 32) + (bc >> 32),
1472 (intermediate << 32) + (bd & mask)};
1476namespace dragonbox {
1479inline auto floor_log10_pow2(
int e)
noexcept ->
int {
1480 FMT_ASSERT(e <= 2620 && e >= -2620,
"too large exponent");
1481 static_assert((-1 >> 1) == -1,
"right shift is not arithmetic");
1482 return (e * 315653) >> 20;
1485inline auto floor_log2_pow10(
int e)
noexcept ->
int {
1486 FMT_ASSERT(e <= 1233 && e >= -1233,
"too large exponent");
1487 return (e * 1741647) >> 19;
1491inline auto umul128_upper64(uint64_t x, uint64_t y)
noexcept ->
uint64_t {
1493 auto p =
static_cast<uint128_opt
>(x) *
static_cast<uint128_opt
>(y);
1494 return static_cast<uint64_t>(p >> 64);
1495#elif defined(_MSC_VER) && defined(_M_X64)
1496 return __umulh(x, y);
1498 return umul128(x, y).high();
1504inline auto umul192_upper128(uint64_t x, uint128_fallback y)
noexcept
1505 -> uint128_fallback {
1506 uint128_fallback r = umul128(x, y.high());
1507 r += umul128_upper64(x, y.low());
1511FMT_API
auto get_cached_power(
int k)
noexcept -> uint128_fallback;
1517 using carrier_uint = uint32_t;
1518 static const int exponent_bits = 8;
1519 static const int kappa = 1;
1520 static const int big_divisor = 100;
1521 static const int small_divisor = 10;
1522 static const int min_k = -31;
1523 static const int max_k = 46;
1524 static const int shorter_interval_tie_lower_threshold = -35;
1525 static const int shorter_interval_tie_upper_threshold = -35;
1529 using carrier_uint = uint64_t;
1530 static const int exponent_bits = 11;
1531 static const int kappa = 2;
1532 static const int big_divisor = 1000;
1533 static const int small_divisor = 100;
1534 static const int min_k = -292;
1535 static const int max_k = 341;
1536 static const int shorter_interval_tie_lower_threshold = -77;
1537 static const int shorter_interval_tie_upper_threshold = -77;
1541template <
typename T>
1542struct float_info<T, enable_if_t<std::numeric_limits<T>::digits == 64 ||
1543 std::numeric_limits<T>::digits == 113 ||
1544 is_float128<T>::value>> {
1545 using carrier_uint = detail::uint128_t;
1546 static const int exponent_bits = 15;
1550template <
typename T>
1552 using carrier_uint = detail::uint128_t;
1557 significand_type significand;
1561template <
typename T> FMT_API
auto to_decimal(T x)
noexcept ->
decimal_fp<T>;
1565template <
typename Float>
constexpr auto has_implicit_bit() ->
bool {
1567 return std::numeric_limits<Float>::digits != 64;
1572template <
typename Float>
constexpr auto num_significand_bits() ->
int {
1574 return is_float128<Float>() ? 112
1575 : (std::numeric_limits<Float>::digits -
1576 (has_implicit_bit<Float>() ? 1 : 0));
1579template <
typename Float>
1580constexpr auto exponent_mask() ->
1581 typename dragonbox::float_info<Float>::carrier_uint {
1582 using float_uint =
typename dragonbox::float_info<Float>::carrier_uint;
1583 return ((float_uint(1) << dragonbox::float_info<Float>::exponent_bits) - 1)
1584 << num_significand_bits<Float>();
1586template <
typename Float>
constexpr auto exponent_bias() ->
int {
1588 return is_float128<Float>() ? 16383
1589 : std::numeric_limits<Float>::max_exponent - 1;
1593template <
typename Char,
typename It>
1594FMT_CONSTEXPR
auto write_exponent(
int exp, It it) -> It {
1595 FMT_ASSERT(-10000 < exp && exp < 10000,
"exponent out of range");
1597 *it++ =
static_cast<Char
>(
'-');
1600 *it++ =
static_cast<Char
>(
'+');
1603 const char* top = digits2(to_unsigned(exp / 100));
1604 if (exp >= 1000) *it++ =
static_cast<Char
>(top[0]);
1605 *it++ =
static_cast<Char
>(top[1]);
1608 const char* d = digits2(to_unsigned(exp));
1609 *it++ =
static_cast<Char
>(d[0]);
1610 *it++ =
static_cast<Char
>(d[1]);
1619 static constexpr const int num_significand_bits =
1620 static_cast<int>(
sizeof(F) * num_bits<unsigned char>());
1622 constexpr basic_fp() : f(0), e(0) {}
1623 constexpr basic_fp(uint64_t f_val,
int e_val) : f(f_val), e(e_val) {}
1626 template <
typename Float> FMT_CONSTEXPR
basic_fp(Float n) { assign(n); }
1629 template <
typename Float, FMT_ENABLE_IF(!is_
double_
double<Float>::value)>
1630 FMT_CONSTEXPR
auto assign(Float n) ->
bool {
1631 static_assert(std::numeric_limits<Float>::digits <= 113,
"unsupported FP");
1634 const auto num_float_significand_bits =
1635 detail::num_significand_bits<Float>();
1636 const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
1637 const auto significand_mask = implicit_bit - 1;
1638 auto u = bit_cast<carrier_uint>(n);
1639 f =
static_cast<F
>(u & significand_mask);
1640 auto biased_e =
static_cast<int>((u & exponent_mask<Float>()) >>
1641 num_float_significand_bits);
1644 auto is_predecessor_closer = f == 0 && biased_e > 1;
1647 else if (has_implicit_bit<Float>())
1648 f +=
static_cast<F
>(implicit_bit);
1649 e = biased_e - exponent_bias<Float>() - num_float_significand_bits;
1650 if (!has_implicit_bit<Float>()) ++e;
1651 return is_predecessor_closer;
1654 template <
typename Float, FMT_ENABLE_IF(is_
double_
double<Float>::value)>
1655 FMT_CONSTEXPR
auto assign(Float n) ->
bool {
1656 static_assert(std::numeric_limits<double>::is_iec559,
"unsupported FP");
1657 return assign(
static_cast<double>(n));
1664template <
int SHIFT = 0,
typename F>
1667 const auto implicit_bit = F(1) << num_significand_bits<double>();
1668 const auto shifted_implicit_bit = implicit_bit << SHIFT;
1669 while ((
value.f & shifted_implicit_bit) == 0) {
1674 const auto offset = basic_fp<F>::num_significand_bits -
1675 num_significand_bits<double>() - SHIFT - 1;
1682FMT_CONSTEXPR
inline auto multiply(uint64_t lhs, uint64_t rhs) ->
uint64_t {
1684 auto product =
static_cast<__uint128_t
>(lhs) * rhs;
1685 auto f =
static_cast<uint64_t>(product >> 64);
1686 return (
static_cast<uint64_t>(product) & (1ULL << 63)) != 0 ? f + 1 : f;
1690 uint64_t a = lhs >> 32, b = lhs & mask;
1691 uint64_t c = rhs >> 32, d = rhs & mask;
1692 uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
1694 uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
1695 return ac + (ad >> 32) + (bc >> 32) + (mid >> 32);
1699FMT_CONSTEXPR
inline auto operator*(fp x, fp y) -> fp {
1700 return {multiply(x.f, y.f), x.e + y.e + 64};
1703template <typename T, bool doublish = num_bits<T>() == num_bits<double>()>
1704using convert_float_result =
1705 conditional_t<std::is_same<T, float>::value || doublish, double, T>;
1707template <
typename T>
1708constexpr auto convert_float(T value) -> convert_float_result<T> {
1709 return static_cast<convert_float_result<T>
>(value);
1712template <
typename Char,
typename OutputIt>
1713FMT_NOINLINE FMT_CONSTEXPR
auto fill(OutputIt it,
size_t n,
const fill_t& fill)
1715 auto fill_size = fill.size();
1716 if (fill_size == 1)
return detail::fill_n(it, n, fill.template get<Char>());
1717 if (
const Char* data = fill.template data<Char>()) {
1718 for (
size_t i = 0; i < n; ++i) it = copy<Char>(data, data + fill_size, it);
1726template <
typename Char, align::type align = align::left,
typename OutputIt,
1728FMT_CONSTEXPR
auto write_padded(OutputIt out,
const format_specs& specs,
1729 size_t size,
size_t width, F&& f) -> OutputIt {
1730 static_assert(align == align::left || align == align::right,
"");
1731 unsigned spec_width = to_unsigned(specs.width);
1732 size_t padding = spec_width > width ? spec_width - width : 0;
1735 auto* shifts = align == align::left ?
"\x1f\x1f\x00\x01" :
"\x00\x1f\x00\x01";
1736 size_t left_padding = padding >> shifts[specs.align];
1737 size_t right_padding = padding - left_padding;
1738 auto it = reserve(out, size + padding * specs.fill.size());
1739 if (left_padding != 0) it = fill<Char>(it, left_padding, specs.fill);
1741 if (right_padding != 0) it = fill<Char>(it, right_padding, specs.fill);
1742 return base_iterator(out, it);
1745template <
typename Char, align::type align = align::left,
typename OutputIt,
1747constexpr auto write_padded(OutputIt out,
const format_specs& specs,
1748 size_t size, F&& f) -> OutputIt {
1749 return write_padded<Char, align>(out, specs, size, size, f);
1752template <
typename Char, align::type align = align::left,
typename OutputIt>
1755 return write_padded<Char, align>(
1756 out, specs,
bytes.size(), [
bytes](reserve_iterator<OutputIt> it) {
1757 const char* data = bytes.data();
1758 return copy<Char>(data, data + bytes.size(), it);
1762template <
typename Char,
typename OutputIt,
typename UIntPtr>
1763auto write_ptr(OutputIt out, UIntPtr value,
const format_specs* specs)
1765 int num_digits = count_digits<4>(value);
1766 auto size = to_unsigned(num_digits) + size_t(2);
1767 auto write = [=](reserve_iterator<OutputIt> it) {
1768 *it++ =
static_cast<Char
>(
'0');
1769 *it++ =
static_cast<Char
>(
'x');
1770 return format_uint<4, Char>(it, value, num_digits);
1772 return specs ? write_padded<Char, align::right>(out, *specs, size, write)
1773 : base_iterator(out, write(reserve(out, size)));
1777FMT_API
auto is_printable(uint32_t cp) -> bool;
1779inline auto needs_escape(uint32_t cp) ->
bool {
1780 return cp < 0x20 || cp == 0x7f || cp ==
'"' || cp ==
'\\' ||
1790template <
typename Char>
1791auto find_escape(
const Char* begin,
const Char* end)
1793 for (; begin != end; ++begin) {
1794 uint32_t cp =
static_cast<unsigned_char<Char>
>(*begin);
1795 if (const_check(
sizeof(Char) == 1) && cp >= 0x80)
continue;
1796 if (needs_escape(cp))
return {begin, begin + 1, cp};
1798 return {begin,
nullptr, 0};
1801inline auto find_escape(
const char* begin,
const char* end)
1802 -> find_escape_result<char> {
1803 if (!use_utf8())
return find_escape<char>(begin, end);
1804 auto result = find_escape_result<char>{end,
nullptr, 0};
1805 for_each_codepoint(
string_view(begin, to_unsigned(end - begin)),
1807 if (needs_escape(cp)) {
1808 result = {sv.begin(), sv.end(), cp};
1816#define FMT_STRING_IMPL(s, base, explicit) \
1820 struct FMT_VISIBILITY("hidden") FMT_COMPILE_STRING : base { \
1821 using char_type FMT_MAYBE_UNUSED = fmt::remove_cvref_t<decltype(s[0])>; \
1822 FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \
1823 operator fmt::basic_string_view<char_type>() const { \
1824 return fmt::detail_exported::compile_string_to_view<char_type>(s); \
1827 return FMT_COMPILE_STRING(); \
1840#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string, )
1842template <
size_t w
idth,
typename Char,
typename OutputIt>
1843auto write_codepoint(OutputIt out,
char prefix, uint32_t cp) -> OutputIt {
1844 *out++ =
static_cast<Char
>(
'\\');
1845 *out++ =
static_cast<Char
>(prefix);
1847 fill_n(buf, width,
static_cast<Char
>(
'0'));
1848 format_uint<4>(buf, cp, width);
1849 return copy<Char>(buf, buf + width, out);
1852template <
typename OutputIt,
typename Char>
1853auto write_escaped_cp(OutputIt out,
const find_escape_result<Char>& escape)
1855 auto c =
static_cast<Char
>(escape.cp);
1856 switch (escape.cp) {
1858 *out++ =
static_cast<Char
>(
'\\');
1859 c =
static_cast<Char
>(
'n');
1862 *out++ =
static_cast<Char
>(
'\\');
1863 c =
static_cast<Char
>(
'r');
1866 *out++ =
static_cast<Char
>(
'\\');
1867 c =
static_cast<Char
>(
't');
1874 *out++ =
static_cast<Char
>(
'\\');
1877 if (escape.cp < 0x100)
return write_codepoint<2, Char>(out,
'x', escape.cp);
1878 if (escape.cp < 0x10000)
1879 return write_codepoint<4, Char>(out,
'u', escape.cp);
1880 if (escape.cp < 0x110000)
1881 return write_codepoint<8, Char>(out,
'U', escape.cp);
1883 escape.begin, to_unsigned(escape.end - escape.begin))) {
1884 out = write_codepoint<2, Char>(out,
'x',
1885 static_cast<uint32_t>(escape_char) & 0xFF);
1893template <
typename Char,
typename OutputIt>
1896 *out++ =
static_cast<Char
>(
'"');
1897 auto begin = str.begin(), end = str.end();
1899 auto escape = find_escape(begin, end);
1900 out = copy<Char>(begin, escape.begin, out);
1903 out = write_escaped_cp<OutputIt, Char>(out, escape);
1904 }
while (begin != end);
1905 *out++ =
static_cast<Char
>(
'"');
1909template <
typename Char,
typename OutputIt>
1910auto write_escaped_char(OutputIt out, Char v) -> OutputIt {
1911 Char v_array[1] = {v};
1912 *out++ =
static_cast<Char
>(
'\'');
1913 if ((needs_escape(
static_cast<uint32_t>(v)) && v !=
static_cast<Char
>(
'"')) ||
1914 v ==
static_cast<Char
>(
'\'')) {
1915 out = write_escaped_cp(out,
1916 find_escape_result<Char>{v_array, v_array + 1,
1921 *out++ =
static_cast<Char
>(
'\'');
1925template <
typename Char,
typename OutputIt>
1926FMT_CONSTEXPR
auto write_char(OutputIt out, Char value,
1928 bool is_debug = specs.type == presentation_type::debug;
1929 return write_padded<Char>(out, specs, 1, [=](reserve_iterator<OutputIt> it) {
1930 if (is_debug)
return write_escaped_char(it, value);
1935template <
typename Char,
typename OutputIt>
1936FMT_CONSTEXPR
auto write(OutputIt out, Char value,
const format_specs& specs,
1937 locale_ref loc = {}) -> OutputIt {
1939 using unsigned_type =
1940 conditional_t<std::is_same<Char, char>::value,
unsigned char,
unsigned>;
1941 return check_char_specs(specs)
1942 ? write_char<Char>(out, value, specs)
1943 : write<Char>(out, static_cast<unsigned_type>(value), specs, loc);
1954 : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) {
1955 if (specs.align == align::numeric) {
1956 auto width = to_unsigned(specs.width);
1958 padding = width - size;
1961 }
else if (specs.precision > num_digits) {
1962 size = (prefix >> 24) + to_unsigned(specs.precision);
1963 padding = to_unsigned(specs.precision - num_digits);
1972template <
typename Char,
typename OutputIt,
typename W>
1973FMT_CONSTEXPR FMT_INLINE
auto write_int(OutputIt out,
int num_digits,
1976 W write_digits) -> OutputIt {
1978 if ((specs.width | (specs.precision + 1)) == 0) {
1979 auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24));
1981 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
1982 *it++ =
static_cast<Char
>(p & 0xff);
1984 return base_iterator(out, write_digits(it));
1986 auto data = write_int_data<Char>(num_digits, prefix, specs);
1987 return write_padded<Char, align::right>(
1988 out, specs, data.size, [=](reserve_iterator<OutputIt> it) {
1989 for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
1990 *it++ = static_cast<Char>(p & 0xff);
1991 it = detail::fill_n(it, data.padding, static_cast<Char>(
'0'));
1992 return write_digits(it);
1998 std::string grouping_;
1999 std::basic_string<Char> thousands_sep_;
2002 std::string::const_iterator group;
2005 auto initial_state()
const -> next_state {
return {grouping_.begin(), 0}; }
2008 auto next(next_state& state)
const ->
int {
2009 if (thousands_sep_.empty())
return max_value<int>();
2010 if (state.group == grouping_.end())
return state.pos += grouping_.back();
2011 if (*state.group <= 0 || *state.group == max_value<char>())
2012 return max_value<int>();
2013 state.pos += *state.group++;
2019 if (!localized)
return;
2020 auto sep = thousands_sep<Char>(loc);
2021 grouping_ = sep.grouping;
2022 if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep);
2024 digit_grouping(std::string grouping, std::basic_string<Char> sep)
2025 : grouping_(std::move(grouping)), thousands_sep_(std::move(sep)) {}
2027 auto has_separator()
const ->
bool {
return !thousands_sep_.empty(); }
2029 auto count_separators(
int num_digits)
const ->
int {
2031 auto state = initial_state();
2032 while (num_digits > next(state)) ++count;
2037 template <
typename Out,
typename C>
2039 auto num_digits =
static_cast<int>(digits.
size());
2041 separators.push_back(0);
2042 auto state = initial_state();
2043 while (
int i = next(state)) {
2044 if (i >= num_digits)
break;
2045 separators.push_back(i);
2047 for (
int i = 0, sep_index =
static_cast<int>(separators.size() - 1);
2048 i < num_digits; ++i) {
2049 if (num_digits - i == separators[sep_index]) {
2050 out = copy<Char>(thousands_sep_.data(),
2051 thousands_sep_.data() + thousands_sep_.size(), out);
2054 *out++ =
static_cast<Char
>(digits[to_unsigned(i)]);
2060FMT_CONSTEXPR
inline void prefix_append(
unsigned& prefix,
unsigned value) {
2062 prefix += (1u + (
value > 0xff ? 1 : 0)) << 24;
2066template <
typename OutputIt,
typename UInt,
typename Char>
2067auto write_int(OutputIt out, UInt value,
unsigned prefix,
2068 const format_specs& specs,
const digit_grouping<Char>& grouping)
2070 static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value,
"");
2073 switch (specs.type) {
2075 FMT_ASSERT(
false,
"");
2077 case presentation_type::none:
2078 case presentation_type::dec:
2079 num_digits = count_digits(value);
2080 format_decimal<char>(
appender(buffer), value, num_digits);
2082 case presentation_type::hex:
2084 prefix_append(prefix,
unsigned(specs.upper ?
'X' :
'x') << 8 |
'0');
2085 num_digits = count_digits<4>(value);
2086 format_uint<4, char>(
appender(buffer), value, num_digits, specs.upper);
2088 case presentation_type::oct:
2089 num_digits = count_digits<3>(value);
2092 if (specs.alt && specs.precision <= num_digits && value != 0)
2093 prefix_append(prefix,
'0');
2094 format_uint<3, char>(
appender(buffer), value, num_digits);
2096 case presentation_type::bin:
2098 prefix_append(prefix,
unsigned(specs.upper ?
'B' :
'b') << 8 |
'0');
2099 num_digits = count_digits<1>(value);
2100 format_uint<1, char>(
appender(buffer), value, num_digits);
2102 case presentation_type::chr:
2103 return write_char<Char>(out,
static_cast<Char
>(value), specs);
2106 unsigned size = (prefix != 0 ? prefix >> 24 : 0) + to_unsigned(num_digits) +
2107 to_unsigned(grouping.count_separators(num_digits));
2108 return write_padded<Char, align::right>(
2109 out, specs, size, size, [&](reserve_iterator<OutputIt> it) {
2110 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
2111 *it++ =
static_cast<Char
>(p & 0xff);
2112 return grouping.apply(it,
string_view(buffer.data(), buffer.size()));
2118 locale_ref loc) -> bool;
2119template <
typename OutputIt>
2130template <
typename T>
2131FMT_CONSTEXPR
auto make_write_int_arg(T
value, sign_t sign)
2134 auto abs_value =
static_cast<uint32_or_64_or_128_t<T>
>(
value);
2135 if (is_negative(
value)) {
2136 prefix = 0x01000000 |
'-';
2137 abs_value = 0 - abs_value;
2139 constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u |
'+',
2141 prefix = prefixes[sign];
2143 return {abs_value, prefix};
2149 std::basic_string<Char> sep;
2150 std::string grouping;
2151 std::basic_string<Char> decimal_point;
2153 template <
typename T, FMT_ENABLE_IF(is_
integer<T>::value)>
2154 auto operator()(T
value) ->
bool {
2155 auto arg = make_write_int_arg(
value, specs.sign);
2156 write_int(out,
static_cast<uint64_or_128_t<T>
>(arg.abs_value), arg.prefix,
2161 template <
typename T, FMT_ENABLE_IF(!is_
integer<T>::value)>
2162 auto operator()(T) ->
bool {
2167template <
typename Char,
typename OutputIt,
typename T>
2171 static_assert(std::is_same<T, uint32_or_64_or_128_t<T>>::value,
"");
2172 auto abs_value = arg.abs_value;
2173 auto prefix = arg.prefix;
2174 switch (specs.type) {
2176 FMT_ASSERT(
false,
"");
2178 case presentation_type::none:
2179 case presentation_type::dec: {
2180 int num_digits = count_digits(abs_value);
2181 return write_int<Char>(
2182 out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
2183 return format_decimal<Char>(it, abs_value, num_digits).end;
2186 case presentation_type::hex: {
2188 prefix_append(prefix,
unsigned(specs.upper ?
'X' :
'x') << 8 |
'0');
2189 int num_digits = count_digits<4>(abs_value);
2190 return write_int<Char>(
2191 out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
2192 return format_uint<4, Char>(it, abs_value, num_digits, specs.upper);
2195 case presentation_type::oct: {
2196 int num_digits = count_digits<3>(abs_value);
2199 if (specs.alt && specs.precision <= num_digits && abs_value != 0)
2200 prefix_append(prefix,
'0');
2201 return write_int<Char>(
2202 out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
2203 return format_uint<3, Char>(it, abs_value, num_digits);
2206 case presentation_type::bin: {
2208 prefix_append(prefix,
unsigned(specs.upper ?
'B' :
'b') << 8 |
'0');
2209 int num_digits = count_digits<1>(abs_value);
2210 return write_int<Char>(
2211 out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
2212 return format_uint<1, Char>(it, abs_value, num_digits);
2215 case presentation_type::chr:
2216 return write_char<Char>(out,
static_cast<Char
>(abs_value), specs);
2219template <
typename Char,
typename OutputIt,
typename T>
2220FMT_CONSTEXPR FMT_NOINLINE
auto write_int_noinline(OutputIt out,
2221 write_int_arg<T> arg,
2223 locale_ref loc) -> OutputIt {
2224 return write_int<Char>(out, arg, specs, loc);
2226template <
typename Char,
typename T,
2227 FMT_ENABLE_IF(is_integral<T>::value &&
2228 !std::is_same<T, bool>::value &&
2229 !std::is_same<T, Char>::value)>
2233 if (specs.localized && write_loc(out, value, specs, loc))
return out;
2234 return write_int_noinline<Char>(out, make_write_int_arg(value, specs.sign),
2238template <
typename Char,
typename OutputIt,
typename T,
2239 FMT_ENABLE_IF(is_integral<T>::value &&
2240 !std::is_same<T, bool>::value &&
2241 !std::is_same<T, Char>::value &&
2243FMT_CONSTEXPR FMT_INLINE
auto write(OutputIt out, T value,
2246 if (specs.localized && write_loc(out, value, specs, loc))
return out;
2247 return write_int<Char>(out, make_write_int_arg(value, specs.sign), specs,
2258 using iterator_category = std::output_iterator_tag;
2259 using difference_type = std::ptrdiff_t;
2260 using pointer = void;
2261 using reference = void;
2265 template <
typename T> FMT_CONSTEXPR
void operator=(
const T&) {}
2270 FMT_CONSTEXPR
auto count() const ->
size_t {
return count_; }
2272 FMT_CONSTEXPR
auto operator++() -> counting_iterator& {
2276 FMT_CONSTEXPR
auto operator++(
int) -> counting_iterator {
2282 FMT_CONSTEXPR
friend auto operator+(counting_iterator it, difference_type n)
2283 -> counting_iterator {
2284 it.count_ +=
static_cast<size_t>(n);
2288 FMT_CONSTEXPR
auto operator*() const -> value_type {
return {}; }
2291template <
typename Char,
typename OutputIt>
2294 auto data = s.data();
2295 auto size = s.size();
2296 if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
2297 size = code_point_index(s, to_unsigned(specs.precision));
2298 bool is_debug = specs.type == presentation_type::debug;
2301 if (is_debug) size = write_escaped_string(counting_iterator{}, s).count();
2303 if (specs.width != 0) {
2309 return write_padded<Char>(out, specs, size, width,
2310 [=](reserve_iterator<OutputIt> it) {
2311 if (is_debug)
return write_escaped_string(it, s);
2312 return copy<Char>(data, data + size, it);
2315template <
typename Char,
typename OutputIt>
2316FMT_CONSTEXPR
auto write(OutputIt out,
2319 return write<Char>(out, s, specs);
2321template <
typename Char,
typename OutputIt>
2322FMT_CONSTEXPR
auto write(OutputIt out,
const Char* s,
const format_specs& specs,
2323 locale_ref) -> OutputIt {
2324 if (specs.type == presentation_type::pointer)
2325 return write_ptr<Char>(out, bit_cast<uintptr_t>(s), &specs);
2326 if (!s) report_error(
"string pointer is null");
2330template <
typename Char,
typename OutputIt,
typename T,
2331 FMT_ENABLE_IF(is_integral<T>::value &&
2332 !std::is_same<T, bool>::value &&
2333 !std::is_same<T, Char>::value)>
2334FMT_CONSTEXPR
auto write(OutputIt out, T value) -> OutputIt {
2335 auto abs_value =
static_cast<uint32_or_64_or_128_t<T>
>(value);
2336 bool negative = is_negative(value);
2338 if (negative) abs_value = ~abs_value + 1;
2339 int num_digits = count_digits(abs_value);
2340 auto size = (negative ? 1 : 0) +
static_cast<size_t>(num_digits);
2341 auto it = reserve(out, size);
2342 if (
auto ptr = to_pointer<Char>(it, size)) {
2343 if (negative) *ptr++ =
static_cast<Char
>(
'-');
2344 format_decimal<Char>(ptr, abs_value, num_digits);
2347 if (negative) *it++ =
static_cast<Char
>(
'-');
2348 it = format_decimal<Char>(it, abs_value, num_digits).end;
2349 return base_iterator(out, it);
2353template <
typename Char>
2354FMT_CONSTEXPR
auto parse_align(
const Char* begin,
const Char* end,
2356 FMT_ASSERT(begin != end,
"");
2357 auto align = align::none;
2358 auto p = begin + code_point_length(begin);
2359 if (end - p <= 0) p = begin;
2361 switch (to_ascii(*p)) {
2363 align = align::left;
2366 align = align::right;
2369 align = align::center;
2372 if (align != align::none) {
2375 if (c ==
'}')
return begin;
2377 report_error(
"invalid fill character '{'");
2386 }
else if (p == begin) {
2391 specs.align = align;
2396enum class float_format :
unsigned char {
2404 float_format format : 8;
2412FMT_CONSTEXPR
inline auto parse_float_type_spec(
const format_specs& specs)
2415 result.showpoint = specs.alt;
2416 result.locale = specs.localized;
2417 switch (specs.type) {
2420 case presentation_type::none:
2421 result.format = float_format::general;
2423 case presentation_type::exp:
2424 result.format = float_format::exp;
2425 result.showpoint |= specs.precision != 0;
2427 case presentation_type::fixed:
2428 result.format = float_format::fixed;
2429 result.showpoint |= specs.precision != 0;
2431 case presentation_type::general:
2432 result.format = float_format::general;
2438template <
typename Char,
typename OutputIt>
2439FMT_CONSTEXPR20
auto write_nonfinite(OutputIt out,
bool isnan,
2443 isnan ? (specs.upper ?
"NAN" :
"nan") : (specs.upper ?
"INF" :
"inf");
2444 constexpr size_t str_size = 3;
2445 auto size = str_size + (sign ? 1 : 0);
2447 const bool is_zero_fill =
2448 specs.fill.size() == 1 && specs.fill.template get<Char>() ==
'0';
2449 if (is_zero_fill) specs.fill =
' ';
2450 return write_padded<Char>(out, specs, size,
2451 [=](reserve_iterator<OutputIt> it) {
2452 if (sign) *it++ = detail::sign<Char>(sign);
2453 return copy<Char>(str, str + str_size, it);
2459 const char* significand;
2460 int significand_size;
2464constexpr auto get_significand_size(
const big_decimal_fp& f) ->
int {
2465 return f.significand_size;
2467template <
typename T>
2468inline auto get_significand_size(
const dragonbox::decimal_fp<T>& f) ->
int {
2469 return count_digits(f.significand);
2472template <
typename Char,
typename OutputIt>
2473constexpr auto write_significand(OutputIt out,
const char* significand,
2474 int significand_size) -> OutputIt {
2475 return copy<Char>(significand, significand + significand_size, out);
2477template <
typename Char,
typename OutputIt,
typename UInt>
2478inline auto write_significand(OutputIt out, UInt significand,
2479 int significand_size) -> OutputIt {
2480 return format_decimal<Char>(out, significand, significand_size).end;
2482template <
typename Char,
typename OutputIt,
typename T,
typename Grouping>
2483FMT_CONSTEXPR20
auto write_significand(OutputIt out, T significand,
2484 int significand_size,
int exponent,
2485 const Grouping& grouping) -> OutputIt {
2486 if (!grouping.has_separator()) {
2487 out = write_significand<Char>(out, significand, significand_size);
2488 return detail::fill_n(out, exponent,
static_cast<Char
>(
'0'));
2491 write_significand<char>(
appender(buffer), significand, significand_size);
2492 detail::fill_n(
appender(buffer), exponent,
'0');
2493 return grouping.apply(out,
string_view(buffer.data(), buffer.size()));
2496template <
typename Char,
typename UInt,
2497 FMT_ENABLE_IF(std::is_integral<UInt>::value)>
2498inline auto write_significand(Char* out, UInt significand,
int significand_size,
2499 int integral_size, Char decimal_point) -> Char* {
2501 return format_decimal(out, significand, significand_size).end;
2502 out += significand_size + 1;
2504 int floating_size = significand_size - integral_size;
2505 for (
int i = floating_size / 2; i > 0; --i) {
2507 copy2(out, digits2(
static_cast<std::size_t
>(significand % 100)));
2510 if (floating_size % 2 != 0) {
2511 *--out =
static_cast<Char
>(
'0' + significand % 10);
2514 *--out = decimal_point;
2515 format_decimal(out - integral_size, significand, integral_size);
2519template <
typename OutputIt,
typename UInt,
typename Char,
2520 FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)>
2521inline auto write_significand(OutputIt out, UInt significand,
2522 int significand_size,
int integral_size,
2523 Char decimal_point) -> OutputIt {
2525 Char buffer[digits10<UInt>() + 2];
2526 auto end = write_significand(buffer, significand, significand_size,
2527 integral_size, decimal_point);
2528 return detail::copy_noinline<Char>(buffer, end, out);
2531template <
typename OutputIt,
typename Char>
2532FMT_CONSTEXPR
auto write_significand(OutputIt out,
const char* significand,
2533 int significand_size,
int integral_size,
2534 Char decimal_point) -> OutputIt {
2535 out = detail::copy_noinline<Char>(significand, significand + integral_size,
2537 if (!decimal_point)
return out;
2538 *out++ = decimal_point;
2539 return detail::copy_noinline<Char>(significand + integral_size,
2540 significand + significand_size, out);
2543template <
typename OutputIt,
typename Char,
typename T,
typename Grouping>
2544FMT_CONSTEXPR20
auto write_significand(OutputIt out, T significand,
2545 int significand_size,
int integral_size,
2547 const Grouping& grouping) -> OutputIt {
2548 if (!grouping.has_separator()) {
2549 return write_significand(out, significand, significand_size, integral_size,
2554 integral_size, decimal_point);
2557 return detail::copy_noinline<Char>(buffer.data() + integral_size,
2561template <
typename Char,
typename OutputIt,
typename DecimalFP,
2562 typename Grouping = digit_grouping<Char>>
2563FMT_CONSTEXPR20
auto do_write_float(OutputIt out,
const DecimalFP& f,
2565 float_specs fspecs, locale_ref loc)
2567 auto significand = f.significand;
2568 int significand_size = get_significand_size(f);
2569 const Char
zero =
static_cast<Char
>(
'0');
2570 auto sign = fspecs.sign;
2571 size_t size = to_unsigned(significand_size) + (sign ? 1 : 0);
2572 using iterator = reserve_iterator<OutputIt>;
2574 Char decimal_point =
2575 fspecs.locale ? detail::decimal_point<Char>(loc) : static_cast<Char>(
'.');
2577 int output_exp = f.exponent + significand_size - 1;
2578 auto use_exp_format = [=]() {
2579 if (fspecs.format == float_format::exp)
return true;
2580 if (fspecs.format != float_format::general)
return false;
2583 const int exp_lower = -4, exp_upper = 16;
2584 return output_exp < exp_lower ||
2585 output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper);
2587 if (use_exp_format()) {
2589 if (fspecs.showpoint) {
2590 num_zeros = fspecs.precision - significand_size;
2591 if (num_zeros < 0) num_zeros = 0;
2592 size += to_unsigned(num_zeros);
2593 }
else if (significand_size == 1) {
2594 decimal_point = Char();
2596 auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp;
2598 if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3;
2600 size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits);
2601 char exp_char = specs.upper ?
'E' :
'e';
2602 auto write = [=](iterator it) {
2603 if (sign) *it++ = detail::sign<Char>(sign);
2605 it = write_significand(it, significand, significand_size, 1,
2607 if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero);
2608 *it++ =
static_cast<Char
>(exp_char);
2609 return write_exponent<Char>(output_exp, it);
2611 return specs.width > 0
2612 ? write_padded<Char, align::right>(out, specs, size, write)
2613 : base_iterator(out, write(reserve(out, size)));
2616 int exp = f.exponent + significand_size;
2617 if (f.exponent >= 0) {
2619 size += to_unsigned(f.exponent);
2620 int num_zeros = fspecs.precision -
exp;
2621 abort_fuzzing_if(num_zeros > 5000);
2622 if (fspecs.showpoint) {
2624 if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 0;
2625 if (num_zeros > 0) size += to_unsigned(num_zeros);
2627 auto grouping = Grouping(loc, fspecs.locale);
2628 size += to_unsigned(grouping.count_separators(exp));
2629 return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
2630 if (sign) *it++ = detail::sign<Char>(sign);
2631 it = write_significand<Char>(it, significand, significand_size,
2632 f.exponent, grouping);
2633 if (!fspecs.showpoint)
return it;
2634 *it++ = decimal_point;
2635 return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
2637 }
else if (exp > 0) {
2639 int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0;
2640 size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0);
2641 auto grouping = Grouping(loc, fspecs.locale);
2642 size += to_unsigned(grouping.count_separators(exp));
2643 return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
2644 if (sign) *it++ = detail::sign<Char>(sign);
2645 it = write_significand(it, significand, significand_size, exp,
2646 decimal_point, grouping);
2647 return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
2651 int num_zeros = -
exp;
2652 if (significand_size == 0 && fspecs.precision >= 0 &&
2653 fspecs.precision < num_zeros) {
2654 num_zeros = fspecs.precision;
2656 bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint;
2657 size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros);
2658 return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
2659 if (sign) *it++ = detail::sign<Char>(sign);
2661 if (!pointy)
return it;
2662 *it++ = decimal_point;
2663 it = detail::fill_n(it, num_zeros, zero);
2664 return write_significand<Char>(it, significand, significand_size);
2672 constexpr auto has_separator()
const ->
bool {
return false; }
2674 constexpr auto count_separators(
int)
const ->
int {
return 0; }
2676 template <
typename Out,
typename C>
2682template <
typename Char,
typename OutputIt,
typename DecimalFP>
2683FMT_CONSTEXPR20
auto write_float(OutputIt out,
const DecimalFP& f,
2686 if (is_constant_evaluated()) {
2687 return do_write_float<Char, OutputIt, DecimalFP,
2691 return do_write_float<Char>(out, f, specs, fspecs, loc);
2695template <
typename T>
constexpr auto isnan(T value) ->
bool {
2696 return value != value;
2699template <
typename T,
typename Enable =
void>
2702template <
typename T>
2704 : std::true_type {};
2706template <
typename T, FMT_ENABLE_IF(std::is_
floating_po
int<T>::value&&
2707 has_isfinite<T>::value)>
2708FMT_CONSTEXPR20
auto isfinite(T
value) ->
bool {
2709 constexpr T inf = T(std::numeric_limits<double>::infinity());
2710 if (is_constant_evaluated())
2711 return !detail::isnan(
value) && value < inf && value > -inf;
2712 return std::isfinite(
value);
2714template <
typename T, FMT_ENABLE_IF(!has_isfinite<T>::value)>
2715FMT_CONSTEXPR
auto isfinite(T value) ->
bool {
2716 T inf = T(std::numeric_limits<double>::infinity());
2718 return !detail::isnan(value) && value < inf && value > -inf;
2721template <
typename T, FMT_ENABLE_IF(is_
floating_po
int<T>::value)>
2722FMT_INLINE FMT_CONSTEXPR
bool signbit(T value) {
2723 if (is_constant_evaluated()) {
2724#ifdef __cpp_if_constexpr
2725 if constexpr (std::numeric_limits<double>::is_iec559) {
2726 auto bits = detail::bit_cast<uint64_t>(
static_cast<double>(value));
2727 return (bits >> (num_bits<uint64_t>() - 1)) != 0;
2731 return std::signbit(
static_cast<double>(value));
2734inline FMT_CONSTEXPR20
void adjust_precision(
int& precision,
int exp10) {
2737 if (exp10 > 0 && precision > max_value<int>() - exp10)
2738 FMT_THROW(format_error(
"number is too big"));
2746 using bigit = uint32_t;
2747 using double_bigit = uint64_t;
2748 enum { bigits_capacity = 32 };
2752 FMT_CONSTEXPR20
auto operator[](
int index)
const -> bigit {
2753 return bigits_[to_unsigned(index)];
2755 FMT_CONSTEXPR20
auto operator[](
int index) -> bigit& {
2756 return bigits_[to_unsigned(index)];
2759 static constexpr const int bigit_bits = num_bits<bigit>();
2763 FMT_CONSTEXPR20
void subtract_bigits(
int index, bigit other, bigit& borrow) {
2764 auto result =
static_cast<double_bigit
>((*this)[index]) - other - borrow;
2765 (*this)[index] =
static_cast<bigit
>(result);
2766 borrow =
static_cast<bigit
>(result >> (bigit_bits * 2 - 1));
2769 FMT_CONSTEXPR20
void remove_leading_zeros() {
2770 int num_bigits =
static_cast<int>(bigits_.
size()) - 1;
2771 while (num_bigits > 0 && (*
this)[num_bigits] == 0) --num_bigits;
2772 bigits_.
resize(to_unsigned(num_bigits + 1));
2776 FMT_CONSTEXPR20
void subtract_aligned(
const bigint& other) {
2777 FMT_ASSERT(other.exp_ >= exp_,
"unaligned bigints");
2778 FMT_ASSERT(compare(*
this, other) >= 0,
"");
2780 int i = other.exp_ - exp_;
2781 for (
size_t j = 0, n = other.bigits_.
size(); j != n; ++i, ++j)
2782 subtract_bigits(i, other.bigits_[j], borrow);
2783 while (borrow > 0) subtract_bigits(i, 0, borrow);
2784 remove_leading_zeros();
2787 FMT_CONSTEXPR20
void multiply(uint32_t
value) {
2788 const double_bigit wide_value =
value;
2790 for (
size_t i = 0, n = bigits_.
size(); i < n; ++i) {
2791 double_bigit result = bigits_[i] * wide_value + carry;
2792 bigits_[i] =
static_cast<bigit
>(result);
2793 carry =
static_cast<bigit
>(result >> bigit_bits);
2795 if (carry != 0) bigits_.push_back(carry);
2798 template <
typename UInt, FMT_ENABLE_IF(std::is_same<UInt, u
int64_t>::value ||
2799 std::is_same<UInt, u
int128_t>::value)>
2800 FMT_CONSTEXPR20
void multiply(UInt
value) {
2802 conditional_t<std::is_same<UInt, uint128_t>::value, uint64_t, uint32_t>;
2803 const int shift = num_bits<half_uint>() - bigit_bits;
2804 const UInt lower =
static_cast<half_uint
>(
value);
2805 const UInt upper =
value >> num_bits<half_uint>();
2807 for (
size_t i = 0, n = bigits_.
size(); i < n; ++i) {
2808 UInt result = lower * bigits_[i] +
static_cast<bigit
>(carry);
2809 carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) +
2810 (carry >> bigit_bits);
2811 bigits_[i] =
static_cast<bigit
>(result);
2813 while (carry != 0) {
2814 bigits_.push_back(
static_cast<bigit
>(carry));
2815 carry >>= bigit_bits;
2819 template <
typename UInt, FMT_ENABLE_IF(std::is_same<UInt, u
int64_t>::value ||
2820 std::is_same<UInt, u
int128_t>::value)>
2821 FMT_CONSTEXPR20
void assign(UInt n) {
2822 size_t num_bigits = 0;
2824 bigits_[num_bigits++] =
static_cast<bigit
>(n);
2827 bigits_.
resize(num_bigits);
2832 FMT_CONSTEXPR20
bigint() : exp_(0) {}
2833 explicit bigint(uint64_t n) { assign(n); }
2836 void operator=(
const bigint&) =
delete;
2838 FMT_CONSTEXPR20
void assign(
const bigint& other) {
2839 auto size = other.bigits_.
size();
2841 auto data = other.bigits_.
data();
2842 copy<bigit>(data, data + size, bigits_.
data());
2846 template <
typename Int> FMT_CONSTEXPR20
void operator=(Int n) {
2847 FMT_ASSERT(n > 0,
"");
2848 assign(uint64_or_128_t<Int>(n));
2851 FMT_CONSTEXPR20
auto num_bigits()
const ->
int {
2852 return static_cast<int>(bigits_.
size()) + exp_;
2855 FMT_NOINLINE FMT_CONSTEXPR20
auto operator<<=(
int shift) ->
bigint& {
2856 FMT_ASSERT(shift >= 0,
"");
2857 exp_ += shift / bigit_bits;
2858 shift %= bigit_bits;
2859 if (shift == 0)
return *
this;
2861 for (
size_t i = 0, n = bigits_.
size(); i < n; ++i) {
2862 bigit c = bigits_[i] >> (bigit_bits - shift);
2863 bigits_[i] = (bigits_[i] << shift) + carry;
2866 if (carry != 0) bigits_.push_back(carry);
2870 template <
typename Int>
2871 FMT_CONSTEXPR20
auto operator*=(Int
value) ->
bigint& {
2872 FMT_ASSERT(
value > 0,
"");
2873 multiply(uint32_or_64_or_128_t<Int>(
value));
2877 friend FMT_CONSTEXPR20
auto compare(
const bigint& lhs,
const bigint& rhs)
2879 int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits();
2880 if (num_lhs_bigits != num_rhs_bigits)
2881 return num_lhs_bigits > num_rhs_bigits ? 1 : -1;
2882 int i =
static_cast<int>(lhs.bigits_.
size()) - 1;
2883 int j =
static_cast<int>(rhs.bigits_.
size()) - 1;
2885 if (end < 0) end = 0;
2886 for (; i >= end; --i, --j) {
2887 bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j];
2888 if (lhs_bigit != rhs_bigit)
return lhs_bigit > rhs_bigit ? 1 : -1;
2890 if (i != j)
return i > j ? 1 : -1;
2895 friend FMT_CONSTEXPR20
auto add_compare(
const bigint& lhs1,
2898 auto minimum = [](
int a,
int b) {
return a < b ? a : b; };
2899 auto maximum = [](
int a,
int b) {
return a > b ? a : b; };
2900 int max_lhs_bigits = maximum(lhs1.num_bigits(), lhs2.num_bigits());
2901 int num_rhs_bigits = rhs.num_bigits();
2902 if (max_lhs_bigits + 1 < num_rhs_bigits)
return -1;
2903 if (max_lhs_bigits > num_rhs_bigits)
return 1;
2904 auto get_bigit = [](
const bigint& n,
int i) -> bigit {
2905 return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0;
2907 double_bigit borrow = 0;
2908 int min_exp = minimum(minimum(lhs1.exp_, lhs2.exp_), rhs.exp_);
2909 for (
int i = num_rhs_bigits - 1; i >= min_exp; --i) {
2911 static_cast<double_bigit
>(get_bigit(lhs1, i)) + get_bigit(lhs2, i);
2912 bigit rhs_bigit = get_bigit(rhs, i);
2913 if (sum > rhs_bigit + borrow)
return 1;
2914 borrow = rhs_bigit + borrow - sum;
2915 if (borrow > 1)
return -1;
2916 borrow <<= bigit_bits;
2918 return borrow != 0 ? -1 : 0;
2922 FMT_CONSTEXPR20
void assign_pow10(
int exp) {
2923 FMT_ASSERT(exp >= 0,
"");
2924 if (exp == 0)
return *
this = 1;
2927 while (exp >= bitmask) bitmask <<= 1;
2933 while (bitmask != 0) {
2935 if ((exp & bitmask) != 0) *
this *= 5;
2941 FMT_CONSTEXPR20
void square() {
2942 int num_bigits =
static_cast<int>(bigits_.
size());
2943 int num_result_bigits = 2 * num_bigits;
2945 bigits_.
resize(to_unsigned(num_result_bigits));
2946 auto sum = uint128_t();
2947 for (
int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) {
2950 for (
int i = 0, j = bigit_index; j >= 0; ++i, --j) {
2952 sum +=
static_cast<double_bigit
>(n[i]) * n[j];
2954 (*this)[bigit_index] =
static_cast<bigit
>(sum);
2955 sum >>= num_bits<bigit>();
2958 for (
int bigit_index = num_bigits; bigit_index < num_result_bigits;
2960 for (
int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;)
2961 sum +=
static_cast<double_bigit
>(n[i++]) * n[j--];
2962 (*this)[bigit_index] =
static_cast<bigit
>(sum);
2963 sum >>= num_bits<bigit>();
2965 remove_leading_zeros();
2971 FMT_CONSTEXPR20
void align(
const bigint& other) {
2972 int exp_difference = exp_ - other.exp_;
2973 if (exp_difference <= 0)
return;
2974 int num_bigits =
static_cast<int>(bigits_.
size());
2975 bigits_.
resize(to_unsigned(num_bigits + exp_difference));
2976 for (
int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j)
2977 bigits_[j] = bigits_[i];
2978 memset(bigits_.
data(), 0, to_unsigned(exp_difference) *
sizeof(bigit));
2979 exp_ -= exp_difference;
2984 FMT_CONSTEXPR20
auto divmod_assign(
const bigint& divisor) ->
int {
2985 FMT_ASSERT(
this != &divisor,
"");
2986 if (compare(*
this, divisor) < 0)
return 0;
2987 FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0,
"");
2991 subtract_aligned(divisor);
2993 }
while (compare(*
this, divisor) >= 0);
3000 predecessor_closer = 1,
3008FMT_CONSTEXPR20
inline void format_dragon(basic_fp<uint128_t> value,
3009 unsigned flags,
int num_digits,
3010 buffer<char>& buf,
int& exp10) {
3016 bigint* upper =
nullptr;
3020 bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0;
3021 int shift = is_predecessor_closer ? 2 : 1;
3023 numerator = value.f;
3024 numerator <<= value.e + shift;
3027 if (is_predecessor_closer) {
3029 upper_store <<= value.e + 1;
3030 upper = &upper_store;
3032 denominator.assign_pow10(exp10);
3033 denominator <<= shift;
3034 }
else if (exp10 < 0) {
3035 numerator.assign_pow10(-exp10);
3036 lower.assign(numerator);
3037 if (is_predecessor_closer) {
3038 upper_store.assign(numerator);
3040 upper = &upper_store;
3042 numerator *= value.f;
3043 numerator <<= shift;
3045 denominator <<= shift - value.e;
3047 numerator = value.f;
3048 numerator <<= shift;
3049 denominator.assign_pow10(exp10);
3050 denominator <<= shift - value.e;
3052 if (is_predecessor_closer) {
3053 upper_store = 1ULL << 1;
3054 upper = &upper_store;
3057 int even =
static_cast<int>((value.f & 1) == 0);
3058 if (!upper) upper = &lower;
3059 bool shortest = num_digits < 0;
3060 if ((flags & dragon::fixup) != 0) {
3061 if (add_compare(numerator, *upper, denominator) + even <= 0) {
3064 if (num_digits < 0) {
3066 if (upper != &lower) *upper *= 10;
3069 if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1);
3075 char* data = buf.data();
3077 int digit = numerator.divmod_assign(denominator);
3078 bool low = compare(numerator, lower) - even < 0;
3080 bool high = add_compare(numerator, *upper, denominator) + even > 0;
3081 data[num_digits++] =
static_cast<char>(
'0' + digit);
3084 ++data[num_digits - 1];
3086 int result = add_compare(numerator, numerator, denominator);
3088 if (result > 0 || (result == 0 && (digit % 2) != 0))
3089 ++data[num_digits - 1];
3091 buf.try_resize(to_unsigned(num_digits));
3092 exp10 -= num_digits - 1;
3097 if (upper != &lower) *upper *= 10;
3101 exp10 -= num_digits - 1;
3102 if (num_digits <= 0) {
3104 if (num_digits == 0) {
3106 digit = add_compare(numerator, numerator, denominator) > 0 ?
'1' :
'0';
3108 buf.push_back(digit);
3111 buf.try_resize(to_unsigned(num_digits));
3112 for (
int i = 0; i < num_digits - 1; ++i) {
3113 int digit = numerator.divmod_assign(denominator);
3114 buf[i] =
static_cast<char>(
'0' + digit);
3117 int digit = numerator.divmod_assign(denominator);
3118 auto result = add_compare(numerator, numerator, denominator);
3119 if (result > 0 || (result == 0 && (digit % 2) != 0)) {
3121 const auto overflow =
'0' + 10;
3122 buf[num_digits - 1] = overflow;
3124 for (
int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) {
3128 if (buf[0] == overflow) {
3130 if ((flags & dragon::fixed) != 0)
3139 buf[num_digits - 1] =
static_cast<char>(
'0' + digit);
3143template <
typename Float, FMT_ENABLE_IF(!is_
double_
double<Float>::value)>
3144FMT_CONSTEXPR20
void format_hexfloat(Float value,
format_specs specs,
3145 buffer<char>& buf) {
3148 static_assert(!std::is_same<Float, float>::value,
"");
3150 using info = dragonbox::float_info<Float>;
3153 using carrier_uint =
typename info::carrier_uint;
3155 constexpr auto num_float_significand_bits =
3156 detail::num_significand_bits<Float>();
3158 basic_fp<carrier_uint> f(value);
3159 f.e += num_float_significand_bits;
3160 if (!has_implicit_bit<Float>()) --f.e;
3162 constexpr auto num_fraction_bits =
3163 num_float_significand_bits + (has_implicit_bit<Float>() ? 1 : 0);
3164 constexpr auto num_xdigits = (num_fraction_bits + 3) / 4;
3166 constexpr auto leading_shift = ((num_xdigits - 1) * 4);
3167 const auto leading_mask = carrier_uint(0xF) << leading_shift;
3168 const auto leading_xdigit =
3169 static_cast<uint32_t>((f.f & leading_mask) >> leading_shift);
3170 if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1);
3172 int print_xdigits = num_xdigits - 1;
3173 if (specs.precision >= 0 && print_xdigits > specs.precision) {
3174 const int shift = ((print_xdigits - specs.precision - 1) * 4);
3175 const auto mask = carrier_uint(0xF) << shift;
3176 const auto v =
static_cast<uint32_t>((f.f & mask) >> shift);
3179 const auto inc = carrier_uint(1) << (shift + 4);
3185 if (!has_implicit_bit<Float>()) {
3186 const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
3187 if ((f.f & implicit_bit) == implicit_bit) {
3193 print_xdigits = specs.precision;
3196 char xdigits[num_bits<carrier_uint>() / 4];
3197 detail::fill_n(xdigits,
sizeof(xdigits),
'0');
3198 format_uint<4>(xdigits, f.f, num_xdigits, specs.upper);
3201 while (print_xdigits > 0 && xdigits[print_xdigits] ==
'0') --print_xdigits;
3204 buf.push_back(specs.upper ?
'X' :
'x');
3205 buf.push_back(xdigits[0]);
3206 if (specs.alt || print_xdigits > 0 || print_xdigits < specs.precision)
3208 buf.append(xdigits + 1, xdigits + 1 + print_xdigits);
3209 for (; print_xdigits < specs.precision; ++print_xdigits) buf.push_back(
'0');
3211 buf.push_back(specs.upper ?
'P' :
'p');
3216 abs_e =
static_cast<uint32_t>(-f.e);
3219 abs_e =
static_cast<uint32_t>(f.e);
3221 format_decimal<char>(
appender(buf), abs_e, detail::count_digits(abs_e));
3224template <
typename Float, FMT_ENABLE_IF(is_
double_
double<Float>::value)>
3225FMT_CONSTEXPR20
void format_hexfloat(Float value,
format_specs specs,
3226 buffer<char>& buf) {
3227 format_hexfloat(
static_cast<double>(value), specs, buf);
3230constexpr auto fractional_part_rounding_thresholds(
int index) ->
uint32_t {
3237 return U
"\x9999999a\x828f5c29\x80418938\x80068db9\x8000a7c6\x800010c7"
3238 U
"\x800001ae\x8000002b"[index];
3241template <
typename Float>
3242FMT_CONSTEXPR20
auto format_float(Float value,
int precision, float_specs specs,
3243 buffer<char>& buf) ->
int {
3245 static_assert(!std::is_same<Float, float>::value,
"");
3246 FMT_ASSERT(value >= 0,
"value is negative");
3247 auto converted_value = convert_float(value);
3249 const bool fixed = specs.format == float_format::fixed;
3251 if (precision <= 0 || !fixed) {
3255 buf.try_resize(to_unsigned(precision));
3256 fill_n(buf.data(), precision,
'0');
3261 bool use_dragon =
true;
3262 unsigned dragon_flags = 0;
3263 if (!is_fast_float<Float>() || is_constant_evaluated()) {
3264 const auto inv_log2_10 = 0.3010299956639812;
3265 using info = dragonbox::float_info<
decltype(converted_value)>;
3266 const auto f = basic_fp<typename info::carrier_uint>(converted_value);
3271 auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10;
3272 exp =
static_cast<int>(e);
3274 dragon_flags = dragon::fixup;
3275 }
else if (precision < 0) {
3277 if (specs.binary32) {
3278 auto dec = dragonbox::to_decimal(
static_cast<float>(value));
3279 write<char>(
appender(buf), dec.significand);
3280 return dec.exponent;
3282 auto dec = dragonbox::to_decimal(
static_cast<double>(value));
3283 write<char>(
appender(buf), dec.significand);
3284 return dec.exponent;
3287 using info = dragonbox::float_info<double>;
3288 auto br = bit_cast<uint64_t>(
static_cast<double>(value));
3291 (
static_cast<uint64_t>(1) << num_significand_bits<double>()) - 1;
3292 uint64_t significand = (br & significand_mask);
3293 int exponent =
static_cast<int>((br & exponent_mask<double>()) >>
3294 num_significand_bits<double>());
3296 if (exponent != 0) {
3297 exponent -= exponent_bias<double>() + num_significand_bits<double>();
3299 (
static_cast<uint64_t>(1) << num_significand_bits<double>());
3303 FMT_ASSERT(significand != 0,
"zeros should not appear here");
3304 int shift = countl_zero(significand);
3305 FMT_ASSERT(shift >= num_bits<uint64_t>() - num_significand_bits<double>(),
3307 shift -= (num_bits<uint64_t>() - num_significand_bits<double>() - 2);
3308 exponent = (std::numeric_limits<double>::min_exponent -
3309 num_significand_bits<double>()) -
3311 significand <<= shift;
3316 const int k = info::kappa - dragonbox::floor_log10_pow2(exponent);
3318 const int beta = exponent + dragonbox::floor_log2_pow10(k);
3320 bool has_more_segments;
3321 int digits_in_the_first_segment;
3323 const auto r = dragonbox::umul192_upper128(
3324 significand << beta, dragonbox::get_cached_power(k));
3325 first_segment = r.high();
3326 has_more_segments = r.low() != 0;
3329 if (first_segment >= 1000000000000000000ULL) {
3330 digits_in_the_first_segment = 19;
3334 digits_in_the_first_segment = 18;
3335 first_segment *= 10;
3340 if (fixed) adjust_precision(precision, exp + digits_in_the_first_segment);
3344 if (digits_in_the_first_segment > precision) {
3347 if (precision <= 0) {
3348 exp += digits_in_the_first_segment;
3350 if (precision < 0) {
3356 if ((first_segment |
static_cast<uint64_t>(has_more_segments)) >
3357 5000000000000000000ULL) {
3365 exp += digits_in_the_first_segment - precision;
3375 dragonbox::umul128_upper64(first_segment, 7922816251426433760ULL) >>
3377 const uint64_t second_third_subsegments =
3378 first_segment - first_subsegment * 10000000000ULL;
3382 bool should_round_up;
3383 int number_of_digits_to_print = precision > 9 ? 9 : precision;
3386 auto print_subsegment = [&](
uint32_t subsegment,
char* buffer) {
3387 int number_of_digits_printed = 0;
3390 if ((number_of_digits_to_print & 1) != 0) {
3396 prod = ((subsegment *
static_cast<uint64_t>(720575941)) >> 24) + 1;
3397 digits =
static_cast<uint32_t>(prod >> 32);
3398 *buffer =
static_cast<char>(
'0' + digits);
3399 number_of_digits_printed++;
3409 prod = ((subsegment *
static_cast<uint64_t>(450359963)) >> 20) + 1;
3410 digits =
static_cast<uint32_t>(prod >> 32);
3411 copy2(buffer, digits2(digits));
3412 number_of_digits_printed += 2;
3416 while (number_of_digits_printed < number_of_digits_to_print) {
3418 digits =
static_cast<uint32_t>(prod >> 32);
3419 copy2(buffer + number_of_digits_printed, digits2(digits));
3420 number_of_digits_printed += 2;
3425 print_subsegment(first_subsegment, buf.data());
3429 if (precision <= 9) {
3443 if (precision < 9) {
3446 fractional_part >= fractional_part_rounding_thresholds(
3447 8 - number_of_digits_to_print) ||
3448 ((fractional_part >> 31) &
3449 ((digits & 1) | (second_third_subsegments != 0) |
3450 has_more_segments)) != 0;
3458 should_round_up = second_third_subsegments > 5000000000ULL ||
3459 (second_third_subsegments == 5000000000ULL &&
3460 ((digits & 1) != 0 || has_more_segments));
3470 static_cast<uint32_t>(dragonbox::umul128_upper64(
3471 second_third_subsegments, 1844674407370955162ULL));
3473 static_cast<uint32_t>(second_third_subsegments) -
3474 second_subsegment * 10;
3476 number_of_digits_to_print = precision - 9;
3477 print_subsegment(second_subsegment, buf.data() + 9);
3480 if (precision < 18) {
3486 fractional_part >= fractional_part_rounding_thresholds(
3487 8 - number_of_digits_to_print) ||
3488 ((fractional_part >> 31) &
3489 ((digits & 1) | (third_subsegment != 0) |
3490 has_more_segments)) != 0;
3497 should_round_up = third_subsegment > 5 ||
3498 (third_subsegment == 5 &&
3499 ((digits & 1) != 0 || has_more_segments));
3504 if (should_round_up) {
3505 ++buf[precision - 1];
3506 for (
int i = precision - 1; i > 0 && buf[i] >
'9'; --i) {
3513 buf[precision++] =
'0';
3518 buf.try_resize(to_unsigned(precision));
3523 exp += digits_in_the_first_segment - 1;
3527 auto f = basic_fp<uint128_t>();
3528 bool is_predecessor_closer = specs.binary32
3529 ? f.assign(
static_cast<float>(value))
3530 : f.assign(converted_value);
3531 if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer;
3532 if (fixed) dragon_flags |= dragon::fixed;
3535 const int max_double_digits = 767;
3536 if (precision > max_double_digits) precision = max_double_digits;
3537 format_dragon(f, dragon_flags, precision, buf, exp);
3539 if (!fixed && !specs.showpoint) {
3541 auto num_digits = buf.size();
3542 while (num_digits > 0 && buf[num_digits - 1] ==
'0') {
3546 buf.try_resize(num_digits);
3551template <
typename Char,
typename OutputIt,
typename T>
3552FMT_CONSTEXPR20
auto write_float(OutputIt out, T value,
format_specs specs,
3553 locale_ref loc) -> OutputIt {
3554 sign_t sign = specs.sign;
3555 if (detail::signbit(value)) {
3558 }
else if (sign == sign::minus) {
3562 if (!detail::isfinite(value))
3563 return write_nonfinite<Char>(out, detail::isnan(value), specs, sign);
3565 if (specs.align == align::numeric && sign) {
3566 auto it = reserve(out, 1);
3567 *it++ = detail::sign<Char>(sign);
3568 out = base_iterator(out, it);
3570 if (specs.width != 0) --specs.width;
3574 if (specs.type == presentation_type::hexfloat) {
3575 if (sign) buffer.push_back(detail::sign<char>(sign));
3576 format_hexfloat(convert_float(value), specs, buffer);
3577 return write_bytes<Char, align::right>(out, {buffer.
data(), buffer.
size()},
3581 int precision = specs.precision >= 0 || specs.type == presentation_type::none
3584 if (specs.type == presentation_type::exp) {
3585 if (precision == max_value<int>())
3586 report_error(
"number is too big");
3589 }
else if (specs.type != presentation_type::fixed && precision == 0) {
3592 float_specs fspecs = parse_float_type_spec(specs);
3594 if (const_check(std::is_same<T, float>())) fspecs.binary32 =
true;
3595 int exp = format_float(convert_float(value), precision, fspecs, buffer);
3596 fspecs.precision = precision;
3597 auto f = big_decimal_fp{buffer.
data(),
static_cast<int>(buffer.
size()), exp};
3598 return write_float<Char>(out, f, specs, fspecs, loc);
3601template <
typename Char,
typename OutputIt,
typename T,
3602 FMT_ENABLE_IF(is_floating_point<T>::value)>
3603FMT_CONSTEXPR20
auto write(OutputIt out, T value,
format_specs specs,
3604 locale_ref loc = {}) -> OutputIt {
3605 if (const_check(!is_supported_floating_point(value)))
return out;
3606 return specs.localized && write_loc(out, value, specs, loc)
3608 : write_float<Char>(out, value, specs, loc);
3611template <
typename Char,
typename OutputIt,
typename T,
3612 FMT_ENABLE_IF(is_fast_float<T>::value)>
3613FMT_CONSTEXPR20
auto write(OutputIt out, T value) -> OutputIt {
3614 if (is_constant_evaluated())
return write<Char>(out, value,
format_specs());
3615 if (const_check(!is_supported_floating_point(value)))
return out;
3617 auto sign = sign_t::none;
3618 if (detail::signbit(value)) {
3624 using floaty = conditional_t<std::is_same<T, long double>::value, double, T>;
3625 using floaty_uint =
typename dragonbox::float_info<floaty>::carrier_uint;
3626 floaty_uint mask = exponent_mask<floaty>();
3627 if ((bit_cast<floaty_uint>(value) & mask) == mask)
3628 return write_nonfinite<Char>(out, std::isnan(value), specs, sign);
3630 auto fspecs = float_specs();
3632 auto dec = dragonbox::to_decimal(
static_cast<floaty
>(value));
3633 return write_float<Char>(out, dec, specs, fspecs, {});
3636template <
typename Char,
typename OutputIt,
typename T,
3637 FMT_ENABLE_IF(is_floating_point<T>::value &&
3638 !is_fast_float<T>::value)>
3639inline auto write(OutputIt out, T value) -> OutputIt {
3643template <
typename Char,
typename OutputIt>
3646 FMT_ASSERT(
false,
"");
3650template <
typename Char,
typename OutputIt>
3653 auto it = reserve(out, value.size());
3654 it = copy_noinline<Char>(value.begin(), value.end(), it);
3655 return base_iterator(out, it);
3658template <
typename Char,
typename OutputIt,
typename T,
3659 FMT_ENABLE_IF(has_to_string_view<T>::value)>
3660constexpr auto write(OutputIt out,
const T& value) -> OutputIt {
3661 return write<Char>(out, to_string_view(value));
3666 typename Char,
typename OutputIt,
typename T,
3668 std::is_enum<T>::value && !std::is_same<T, Char>::value &&
3669 mapped_type_constant<T, basic_format_context<OutputIt, Char>>::value !=
3671 FMT_ENABLE_IF(check)>
3672FMT_CONSTEXPR
auto write(OutputIt out, T value) -> OutputIt {
3673 return write<Char>(out,
static_cast<underlying_t<T>
>(value));
3676template <
typename Char,
typename OutputIt,
typename T,
3677 FMT_ENABLE_IF(std::is_same<T, bool>::value)>
3678FMT_CONSTEXPR
auto write(OutputIt out, T value,
const format_specs& specs = {},
3679 locale_ref = {}) -> OutputIt {
3680 return specs.type != presentation_type::none &&
3681 specs.type != presentation_type::string
3682 ? write<Char>(out, value ? 1 : 0, specs, {})
3683 : write_bytes<Char>(out, value ?
"true" :
"false", specs);
3686template <
typename Char,
typename OutputIt>
3687FMT_CONSTEXPR
auto write(OutputIt out, Char value) -> OutputIt {
3688 auto it = reserve(out, 1);
3690 return base_iterator(out, it);
3693template <
typename Char,
typename OutputIt>
3694FMT_CONSTEXPR20
auto write(OutputIt out,
const Char* value) -> OutputIt {
3696 report_error(
"string pointer is null");
3700template <
typename Char,
typename OutputIt,
typename T,
3701 FMT_ENABLE_IF(std::is_same<T, void>::value)>
3702auto write(OutputIt out,
const T* value,
const format_specs& specs = {},
3703 locale_ref = {}) -> OutputIt {
3704 return write_ptr<Char>(out, bit_cast<uintptr_t>(value), &specs);
3708template <
typename Char,
typename OutputIt,
typename T,
3709 typename Context = basic_format_context<OutputIt, Char>>
3710FMT_CONSTEXPR
auto write(OutputIt out,
const T& value) -> enable_if_t<
3711 std::is_class<T>::value && !has_to_string_view<T>::value &&
3712 !is_floating_point<T>::value && !std::is_same<T, Char>::value &&
3713 !std::is_same<T, remove_cvref_t<decltype(arg_mapper<Context>().map(
3716 return write<Char>(out, arg_mapper<Context>().map(value));
3719template <
typename Char,
typename OutputIt,
typename T,
3720 typename Context = basic_format_context<OutputIt, Char>>
3721FMT_CONSTEXPR
auto write(OutputIt out,
const T& value)
3722 -> enable_if_t<mapped_type_constant<T, Context>::value ==
3723 type::custom_type &&
3724 !std::is_fundamental<T>::value,
3726 auto formatter =
typename Context::template formatter_type<T>();
3727 auto parse_ctx =
typename Context::parse_context_type({});
3729 auto ctx = Context(out, {}, {});
3737 using context = buffered_context<Char>;
3743 template <
typename T>
auto operator()(T
value) ->
iterator {
3744 return write<Char>(out,
value);
3748 context format_ctx(out, args, loc);
3749 h.format(parse_ctx, format_ctx);
3750 return format_ctx.out();
3756 using context = buffered_context<Char>;
3762 template <
typename T>
3763 FMT_CONSTEXPR FMT_INLINE
auto operator()(T
value) ->
iterator {
3764 return detail::write<Char>(out,
value, specs, locale);
3774 template <
typename T, FMT_ENABLE_IF(is_
integer<T>::value)>
3775 FMT_CONSTEXPR
auto operator()(T
value) ->
unsigned long long {
3776 if (is_negative(
value)) report_error(
"negative width");
3777 return static_cast<unsigned long long>(
value);
3780 template <
typename T, FMT_ENABLE_IF(!is_
integer<T>::value)>
3781 FMT_CONSTEXPR
auto operator()(T) ->
unsigned long long {
3782 report_error(
"width is not integer");
3788 template <
typename T, FMT_ENABLE_IF(is_
integer<T>::value)>
3789 FMT_CONSTEXPR
auto operator()(T
value) ->
unsigned long long {
3790 if (is_negative(
value)) report_error(
"negative precision");
3791 return static_cast<unsigned long long>(
value);
3794 template <
typename T, FMT_ENABLE_IF(!is_
integer<T>::value)>
3795 FMT_CONSTEXPR
auto operator()(T) ->
unsigned long long {
3796 report_error(
"precision is not integer");
3801template <
typename Handler,
typename FormatArg>
3802FMT_CONSTEXPR
auto get_dynamic_spec(FormatArg arg) ->
int {
3803 unsigned long long value = arg.visit(Handler());
3804 if (
value > to_unsigned(max_value<int>())) report_error(
"number is too big");
3805 return static_cast<int>(
value);
3808template <
typename Context,
typename ID>
3809FMT_CONSTEXPR
auto get_arg(Context& ctx, ID
id) ->
decltype(ctx.arg(
id)) {
3810 auto arg = ctx.arg(
id);
3811 if (!arg) report_error(
"argument not found");
3815template <
typename Handler,
typename Context>
3816FMT_CONSTEXPR
void handle_dynamic_spec(
int& value,
3817 arg_ref<typename Context::char_type> ref,
3820 case arg_id_kind::none:
3822 case arg_id_kind::index:
3823 value = detail::get_dynamic_spec<Handler>(get_arg(ctx, ref.val.index));
3825 case arg_id_kind::name:
3826 value = detail::get_dynamic_spec<Handler>(get_arg(ctx, ref.val.name));
3831#if FMT_USE_USER_DEFINED_LITERALS
3832# if FMT_USE_NONTYPE_TEMPLATE_ARGS
3833template <
typename T,
typename Char,
size_t N,
3834 fmt::detail_exported::fixed_string<Char, N> Str>
3835struct statically_named_arg : view {
3836 static constexpr auto name = Str.data;
3839 statically_named_arg(
const T& v) : value(v) {}
3842template <
typename T,
typename Char,
size_t N,
3843 fmt::detail_exported::fixed_string<Char, N> Str>
3844struct is_named_arg<statically_named_arg<T, Char, N, Str>> : std::true_type {};
3846template <
typename T,
typename Char,
size_t N,
3847 fmt::detail_exported::fixed_string<Char, N> Str>
3848struct is_statically_named_arg<statically_named_arg<T, Char, N, Str>>
3849 : std::true_type {};
3851template <
typename Char,
size_t N,
3852 fmt::detail_exported::fixed_string<Char, N> Str>
3854 template <
typename T>
auto operator=(T&& value)
const {
3855 return statically_named_arg<T, Char, N, Str>(std::forward<T>(value));
3859template <
typename Char>
struct udl_arg {
3862 template <
typename T>
auto operator=(T&& value)
const -> named_arg<Char, T> {
3863 return {str, std::forward<T>(value)};
3869template <
typename Locale,
typename Char>
3872 -> std::basic_string<Char> {
3875 return {buf.data(), buf.size()};
3880FMT_API
void format_error_code(buffer<char>& out,
int error_code,
3883using fmt::report_error;
3884FMT_API
void report_error(format_func func,
int error_code,
3885 const char* message)
noexcept;
3888FMT_API
auto vsystem_error(
int error_code,
string_view format_str,
3908template <
typename... T>
3910 -> std::system_error {
3911 return vsystem_error(error_code, fmt, fmt::make_format_args(args...));
3931 const char* message)
noexcept;
3935FMT_API
void report_system_error(
int error_code,
const char* message)
noexcept;
3942 enum { buffer_size = std::numeric_limits<unsigned long long>::digits10 + 3 };
3943 mutable char buffer_[buffer_size];
3946 template <
typename UInt>
auto format_unsigned(UInt value) ->
char* {
3947 auto n =
static_cast<detail::uint32_or_64_or_128_t<UInt>
>(value);
3948 return detail::format_decimal(buffer_, n, buffer_size - 1).begin;
3951 template <
typename Int>
auto format_signed(Int value) ->
char* {
3952 auto abs_value =
static_cast<detail::uint32_or_64_or_128_t<Int>
>(value);
3953 bool negative = value < 0;
3954 if (negative) abs_value = 0 - abs_value;
3955 auto begin = format_unsigned(abs_value);
3956 if (negative) *--begin =
'-';
3961 explicit format_int(
int value) : str_(format_signed(value)) {}
3962 explicit format_int(
long value) : str_(format_signed(value)) {}
3963 explicit format_int(
long long value) : str_(format_signed(value)) {}
3964 explicit format_int(
unsigned value) : str_(format_unsigned(value)) {}
3965 explicit format_int(
unsigned long value) : str_(format_unsigned(value)) {}
3966 explicit format_int(
unsigned long long value)
3967 : str_(format_unsigned(value)) {}
3971 return detail::to_unsigned(buffer_ - str_ + buffer_size - 1);
3978 auto data() const -> const
char* {
return str_; }
3985 buffer_[buffer_size - 1] =
'\0';
3994 auto str() const -> std::
string {
return std::string(str_,
size()); }
3997template <
typename T,
typename Char>
3998struct formatter<T, Char, enable_if_t<detail::has_format_as<T>::value>>
3999 :
formatter<detail::format_as_t<T>, Char> {
4000 template <
typename FormatContext>
4001 auto format(
const T& value, FormatContext& ctx)
const ->
decltype(ctx.out()) {
4004 auto&& val = format_as(value);
4005 return base::format(val, ctx);
4009#define FMT_FORMAT_AS(Type, Base) \
4010 template <typename Char> \
4011 struct formatter<Type, Char> : formatter<Base, Char> {}
4013FMT_FORMAT_AS(
signed char,
int);
4014FMT_FORMAT_AS(
unsigned char,
unsigned);
4015FMT_FORMAT_AS(
short,
int);
4016FMT_FORMAT_AS(
unsigned short,
unsigned);
4017FMT_FORMAT_AS(
long, detail::long_type);
4018FMT_FORMAT_AS(
unsigned long, detail::ulong_type);
4019FMT_FORMAT_AS(Char*,
const Char*);
4020FMT_FORMAT_AS(std::nullptr_t,
const void*);
4022FMT_FORMAT_AS(
void*,
const void*);
4024template <
typename Char,
typename Traits,
typename Allocator>
4025class formatter<std::basic_string<Char, Traits, Allocator>, Char>
4026 :
public formatter<basic_string_view<Char>, Char> {};
4028template <
typename Char,
size_t N>
4040template <
typename T>
auto ptr(T p) ->
const void* {
4041 static_assert(std::is_pointer<T>::value,
"");
4042 return detail::bit_cast<const void*>(p);
4055template <
typename Enum>
4056constexpr auto underlying(Enum e)
noexcept -> underlying_t<Enum> {
4057 return static_cast<underlying_t<Enum>
>(e);
4061template <
typename Enum, FMT_ENABLE_IF(std::is_enum<Enum>::value)>
4062constexpr auto format_as(Enum e)
noexcept -> underlying_t<Enum> {
4063 return static_cast<underlying_t<Enum>
>(e);
4081 template <
typename ParseContext>
4082 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
const char* {
4083 return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
4084 detail::type::string_type);
4087 template <
typename FormatContext>
4088 auto format(
bytes b, FormatContext& ctx)
const ->
decltype(ctx.out()) {
4089 auto specs = specs_;
4090 detail::handle_dynamic_spec<detail::width_checker>(specs.width,
4091 specs.width_ref, ctx);
4092 detail::handle_dynamic_spec<detail::precision_checker>(
4093 specs.precision, specs.precision_ref, ctx);
4094 return detail::write_bytes<char>(ctx.out(), b.data_, specs);
4123 template <
typename ParseContext>
4124 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
const char* {
4125 return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
4126 detail::type::int_type);
4129 template <
typename FormatContext>
4131 ->
decltype(ctx.out()) {
4132 auto specs = specs_;
4133 detail::handle_dynamic_spec<detail::width_checker>(specs.width,
4134 specs.width_ref, ctx);
4135 detail::handle_dynamic_spec<detail::precision_checker>(
4136 specs.precision, specs.precision_ref, ctx);
4137 auto arg = detail::make_write_int_arg(t.value, specs.sign);
4138 return detail::write_int(
4139 ctx.out(),
static_cast<detail::uint64_or_128_t<T>
>(arg.abs_value),
4149template <
typename T,
typename Char>
4151 template <
typename ParseContext>
4152 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
decltype(ctx.begin()) {
4155 template <
typename FormatContext>
4157 ->
decltype(ctx.out()) {
4158 return view.fmt->format(*view.value, ctx);
4173 ->
decltype(ctx.
begin()) {
4175 auto it = parse_format_specs(ctx.
begin(), ctx.
end(), specs, ctx,
4176 detail::type::none_type);
4177 width_ = specs.width;
4179 align_ = specs.align;
4181 return formatter_.parse(ctx);
4184 template <
typename FormatContext,
typename F>
4185 auto write_padded(FormatContext& ctx, F write)
const ->
decltype(ctx.out()) {
4186 if (width_ == 0)
return write(ctx.out());
4190 specs.width = width_;
4192 specs.align = align_;
4193 return detail::write<Char>(
4213template <
typename T, FMT_ENABLE_IF(!std::is_
integral<T>::value &&
4214 !detail::has_format_as<T>::value)>
4215inline auto to_string(
const T& value) -> std::string {
4217 detail::write<char>(
appender(buffer), value);
4218 return {buffer.
data(), buffer.
size()};
4221template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
4222FMT_NODISCARD
inline auto to_string(T value) -> std::string {
4225 constexpr int max_size = detail::digits10<T>() + 2;
4226 char buffer[max_size > 5 ?
static_cast<unsigned>(max_size) : 5];
4227 char* begin = buffer;
4228 return std::string(begin, detail::write<char>(begin, value));
4231template <
typename Char,
size_t SIZE>
4233 -> std::basic_string<Char> {
4234 auto size = buf.size();
4235 detail::assume(size < std::basic_string<Char>().max_size());
4236 return std::basic_string<Char>(buf.data(), size);
4239template <
typename T, FMT_ENABLE_IF(!std::is_
integral<T>::value &&
4240 detail::has_format_as<T>::value)>
4241inline auto to_string(
const T& value) -> std::string {
4242 return to_string(format_as(value));
4249template <
typename Char>
4251 typename vformat_args<Char>::type args, locale_ref loc) {
4253 if (fmt.
size() == 2 && equal2(fmt.
data(),
"{}")) {
4254 auto arg = args.get(0);
4255 if (!arg) report_error(
"argument not found");
4256 arg.visit(default_arg_formatter<Char>{out, args, loc});
4260 struct format_handler {
4262 buffered_context<Char>
context;
4267 : parse_context(str),
context(p_out, p_args, p_loc) {}
4269 void on_text(
const Char* begin,
const Char* end) {
4274 FMT_CONSTEXPR
auto on_arg_id() ->
int {
4277 FMT_CONSTEXPR
auto on_arg_id(
int id) ->
int {
4283 int arg_id =
context.arg_id(
id);
4284 if (arg_id < 0) report_error(
"argument not found");
4288 FMT_INLINE
void on_replacement_field(
int id,
const Char*) {
4289 auto arg = get_arg(
context,
id);
4290 context.advance_to(arg.visit(default_arg_formatter<Char>{
4291 context.out(), context.args(), context.locale()}));
4294 auto on_format_specs(
int id,
const Char* begin,
const Char* end)
4296 auto arg = get_arg(
context,
id);
4298 if (arg.format_custom(begin, parse_context,
context))
4299 return parse_context.
begin();
4301 begin = parse_format_specs(begin, end, specs, parse_context, arg.type());
4302 detail::handle_dynamic_spec<detail::width_checker>(
4303 specs.width, specs.width_ref,
context);
4304 detail::handle_dynamic_spec<detail::precision_checker>(
4305 specs.precision, specs.precision_ref,
context);
4306 if (begin == end || *begin !=
'}')
4307 report_error(
"missing '}' in format string");
4309 arg_formatter<Char>{context.out(), specs, context.locale()}));
4313 FMT_NORETURN
void on_error(
const char* message) { report_error(message); }
4315 detail::parse_format_string<false>(fmt, format_handler(out, fmt, args, loc));
4320#ifndef FMT_HEADER_ONLY
4321extern template FMT_API
void vformat_to(buffer<char>&,
string_view,
4322 typename vformat_args<>::type,
4324extern template FMT_API
auto thousands_sep_impl<char>(locale_ref)
4325 -> thousands_sep_result<char>;
4326extern template FMT_API
auto thousands_sep_impl<wchar_t>(locale_ref)
4327 -> thousands_sep_result<wchar_t>;
4328extern template FMT_API
auto decimal_point_impl(locale_ref) -> char;
4329extern template FMT_API
auto decimal_point_impl(locale_ref) -> wchar_t;
4332template <
typename T,
typename Char, type TYPE>
4333template <
typename FormatContext>
4334FMT_CONSTEXPR FMT_INLINE
auto native_formatter<T, Char, TYPE>::format(
4335 const T& val, FormatContext& ctx)
const ->
decltype(ctx.out()) {
4336 if (specs_.width_ref.kind == arg_id_kind::none &&
4337 specs_.precision_ref.kind == arg_id_kind::none) {
4338 return write<Char>(ctx.out(), val, specs_, ctx.locale());
4340 auto specs = specs_;
4341 handle_dynamic_spec<width_checker>(specs.width, specs.width_ref, ctx);
4342 handle_dynamic_spec<precision_checker>(specs.precision, specs.precision_ref,
4344 return write<Char>(ctx.out(), val, specs, ctx.locale());
4352template <
typename Char>
4355 detail::type::float_type> {};
4357#if FMT_USE_USER_DEFINED_LITERALS
4358inline namespace literals {
4369# if FMT_USE_NONTYPE_TEMPLATE_ARGS
4370template <detail_exported::fixed_
string Str>
constexpr auto operator""_a() {
4371 using char_t = remove_cvref_t<
decltype(Str.data[0])>;
4372 return detail::udl_arg<char_t,
sizeof(Str.data) /
sizeof(char_t), Str>();
4375constexpr auto operator""_a(
const char* s,
size_t) -> detail::udl_arg<char> {
4395template <
typename... T>
4398 return vformat(fmt, fmt::make_format_args(args...));
4401template <
typename Locale, FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
4404 return detail::vformat(loc, fmt, args);
4407template <
typename Locale,
typename... T,
4408 FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
4411 return fmt::vformat(loc,
string_view(fmt), fmt::make_format_args(args...));
4414template <
typename OutputIt,
typename Locale,
4416 detail::is_locale<Locale>::value)>
4417auto vformat_to(OutputIt out,
const Locale& loc,
string_view fmt,
4419 using detail::get_buffer;
4420 auto&& buf = get_buffer<char>(out);
4422 return detail::get_iterator(buf, out);
4425template <
typename OutputIt,
typename Locale,
typename... T,
4427 detail::is_locale<Locale>::value)>
4428FMT_INLINE
auto format_to(OutputIt out,
const Locale& loc,
4430 return vformat_to(out, loc, fmt, fmt::make_format_args(args...));
4433template <
typename Locale,
typename... T,
4434 FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
4435FMT_NODISCARD FMT_INLINE
auto formatted_size(
const Locale& loc,
4437 T&&... args) ->
size_t {
4439 detail::vformat_to<char>(buf, fmt, fmt::make_format_args(args...),
4448#ifdef FMT_HEADER_ONLY
4449# define FMT_FUNC inline
4450# include "format-inl.h"
4456#ifdef FMT_REMOVE_TRANSITIVE_INCLUDES
4457# undef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES
FMT_CONSTEXPR auto next_arg_id() -> int
Definition base.h:764
constexpr auto end() const noexcept -> iterator
Definition base.h:753
FMT_CONSTEXPR void check_arg_id(int id)
Definition base.h:778
FMT_CONSTEXPR void advance_to(iterator it)
Definition base.h:756
constexpr auto begin() const noexcept -> iterator
Definition base.h:746
FMT_CONSTEXPR20 void resize(size_t count)
Definition format.h:937
auto operator=(basic_memory_buffer &&other) noexcept -> basic_memory_buffer &
Definition format.h:923
void reserve(size_t new_capacity)
Definition format.h:940
FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer &&other) noexcept
Definition format.h:913
constexpr auto size() const noexcept -> size_t
Definition base.h:526
constexpr auto data() const noexcept -> const Char *
Definition base.h:523
FMT_CONSTEXPR void set(T *buf_data, size_t buf_capacity) noexcept
Definition base.h:861
void clear()
Definition base.h:890
constexpr auto size() const noexcept -> size_t
Definition base.h:880
constexpr auto capacity() const noexcept -> size_t
Definition base.h:883
FMT_CONSTEXPR auto data() noexcept -> T *
Definition base.h:886
GLM_FUNC_QUALIFIER vec< L, T, Q > exp(vec< L, T, Q > const &x)
Definition func_exponential.inl:80
GLM_FUNC_DECL GLM_CONSTEXPR genType zero()
Definition constants.inl:6
uint64 uint64_t
Definition fwd.hpp:145
uint32 uint32_t
Definition fwd.hpp:131
uint8 uint8_t
Definition fwd.hpp:103
GLM_FUNC_DECL qua< T, Q > intermediate(qua< T, Q > const &prev, qua< T, Q > const &curr, qua< T, Q > const &next)
Definition quaternion.inl:40