41 #include <system_error> 44 #ifdef __cpp_lib_bit_cast 51 # define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) 53 # define FMT_GCC_VISIBILITY_HIDDEN 57 # define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__) 59 # define FMT_CUDA_VERSION 0 63 # define FMT_HAS_BUILTIN(x) __has_builtin(x) 65 # define FMT_HAS_BUILTIN(x) 0 68 #if FMT_GCC_VERSION || FMT_CLANG_VERSION 69 # define FMT_NOINLINE __attribute__((noinline)) 75 # define FMT_MSC_DEFAULT = default 77 # define FMT_MSC_DEFAULT 82 # if FMT_MSC_VER || FMT_NVCC 85 template <
typename Exception>
inline void do_throw(
const Exception& x) {
88 volatile bool b =
true;
93 # define FMT_THROW(x) detail::do_throw(x) 95 # define FMT_THROW(x) throw x 98 # define FMT_THROW(x) \ 100 FMT_ASSERT(false, (x).what()); \ 107 # define FMT_CATCH(x) catch (x) 109 # define FMT_TRY if (true) 110 # define FMT_CATCH(x) if (false) 113 #ifndef FMT_MAYBE_UNUSED 114 # if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) 115 # define FMT_MAYBE_UNUSED [[maybe_unused]] 117 # define FMT_MAYBE_UNUSED 122 #if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC 123 # define FMT_DEPRECATED_ALIAS 125 # define FMT_DEPRECATED_ALIAS FMT_DEPRECATED 128 #ifndef FMT_USE_USER_DEFINED_LITERALS 130 # if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \ 131 FMT_MSC_VER >= 1900) && \ 132 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 480) 133 # define FMT_USE_USER_DEFINED_LITERALS 1 135 # define FMT_USE_USER_DEFINED_LITERALS 0 143 #if !defined(FMT_REDUCE_INT_INSTANTIATIONS) 144 # define FMT_REDUCE_INT_INSTANTIATIONS 0 150 # if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION 151 # define FMT_BUILTIN_CLZ(n) __builtin_clz(n) 153 # if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION 154 # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) 161 # if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION 162 # define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) 164 # if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || FMT_ICC_VERSION 165 # define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) 176 #if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(FMT_BUILTIN_CTZLL) 180 # if !defined(__clang__) 181 # pragma intrinsic(_BitScanForward) 182 # pragma intrinsic(_BitScanReverse) 184 # pragma intrinsic(_BitScanForward64) 185 # pragma intrinsic(_BitScanReverse64) 189 inline auto clz(uint32_t x) ->
int {
191 _BitScanReverse(&r, x);
192 FMT_ASSERT(x != 0,
"");
196 FMT_MSC_WARNING(suppress : 6102)
197 return 31 ^
static_cast<int>(r);
199 # define FMT_BUILTIN_CLZ(n) detail::clz(n) 201 inline auto clzll(uint64_t x) ->
int {
204 _BitScanReverse64(&r, x);
207 if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
return 63 ^ (r + 32);
209 _BitScanReverse(&r, static_cast<uint32_t>(x));
211 FMT_ASSERT(x != 0,
"");
212 FMT_MSC_WARNING(suppress : 6102)
213 return 63 ^
static_cast<int>(r);
215 # define FMT_BUILTIN_CLZLL(n) detail::clzll(n) 217 inline auto ctz(uint32_t x) ->
int {
219 _BitScanForward(&r, x);
220 FMT_ASSERT(x != 0,
"");
221 FMT_MSC_WARNING(suppress : 6102)
222 return static_cast<int>(r);
224 # define FMT_BUILTIN_CTZ(n) detail::ctz(n) 226 inline auto ctzll(uint64_t x) ->
int {
228 FMT_ASSERT(x != 0,
"");
229 FMT_MSC_WARNING(suppress : 6102)
231 _BitScanForward64(&r, x);
234 if (_BitScanForward(&r, static_cast<uint32_t>(x)))
return static_cast<int>(r);
236 _BitScanForward(&r, static_cast<uint32_t>(x >> 32));
239 return static_cast<int>(r);
241 # define FMT_BUILTIN_CTZLL(n) detail::ctzll(n) 246 #ifdef FMT_HEADER_ONLY 247 # define FMT_HEADER_ONLY_CONSTEXPR20 FMT_CONSTEXPR20 249 # define FMT_HEADER_ONLY_CONSTEXPR20 255 template <
typename Streambuf>
class formatbuf :
public Streambuf {
257 using char_type =
typename Streambuf::char_type;
258 using streamsize = decltype(std::declval<Streambuf>().sputn(
nullptr, 0));
259 using int_type =
typename Streambuf::int_type;
260 using traits_type =
typename Streambuf::traits_type;
274 auto overflow(int_type ch) -> int_type
override {
275 if (!traits_type::eq_int_type(ch, traits_type::eof()))
276 buffer_.push_back(static_cast<char_type>(ch));
280 auto xsputn(
const char_type* s, streamsize count) -> streamsize
override {
281 buffer_.
append(s, s + count);
287 template <
typename To,
typename From>
288 FMT_CONSTEXPR20
auto bit_cast(
const From& from) -> To {
289 static_assert(
sizeof(To) ==
sizeof(From),
"size mismatch");
290 #ifdef __cpp_lib_bit_cast 291 if (is_constant_evaluated())
return std::bit_cast<To>(from);
294 std::memcpy(&to, &from,
sizeof(to));
298 inline auto is_big_endian() ->
bool {
301 #elif defined(__BIG_ENDIAN__) 303 #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) 304 return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;
307 char data[
sizeof(int)];
309 return bit_cast<
bytes>(1).data[0] == 0;
315 unsigned char value[
sizeof(
void*)];
320 if (const_check(is_big_endian())) {
321 for (
size_t i = 0, j =
sizeof(
void*) - 1; i < j; ++i, --j)
328 inline auto to_uintptr(
const void* p) ->
uintptr_t {
340 template <
typename T> constexpr
auto max_value() -> T {
341 return (std::numeric_limits<T>::max)();
343 template <
typename T> constexpr
auto num_bits() ->
int {
344 return std::numeric_limits<T>::digits;
347 template <> constexpr
auto num_bits<int128_t>() ->
int {
return 128; }
348 template <> constexpr
auto num_bits<uint128_t>() ->
int {
return 128; }
349 template <> constexpr
auto num_bits<fallback_uintptr>() ->
int {
350 return static_cast<int>(
sizeof(
void*) *
351 std::numeric_limits<unsigned char>::digits);
354 FMT_INLINE
void assume(
bool condition) {
356 #if FMT_HAS_BUILTIN(__builtin_assume) 357 __builtin_assume(condition);
362 template <
typename T>
363 using iterator_t = decltype(std::begin(std::declval<T&>()));
364 template <
typename T>
using sentinel_t = decltype(std::end(std::declval<T&>()));
367 template <
typename Char>
368 inline auto get_data(std::basic_string<Char>& s) -> Char* {
371 template <
typename Container>
372 inline auto get_data(Container& c) ->
typename Container::value_type* {
376 #if defined(_SECURE_SCL) && _SECURE_SCL 378 template <
typename T>
using checked_ptr = stdext::checked_array_iterator<T*>;
379 template <
typename T>
380 constexpr
auto make_checked(T* p,
size_t size) -> checked_ptr<T> {
384 template <
typename T>
using checked_ptr = T*;
385 template <
typename T> constexpr
auto make_checked(T* p,
size_t) -> T* {
392 template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
393 #
if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION
394 __attribute__((no_sanitize(
"undefined")))
397 reserve(std::back_insert_iterator<Container> it,
size_t n)
398 -> checked_ptr<typename Container::value_type> {
399 Container& c = get_container(it);
400 size_t size = c.size();
402 return make_checked(get_data(c) + size, n);
405 template <
typename T>
406 inline auto reserve(buffer_appender<T> it,
size_t n) -> buffer_appender<T> {
408 buf.try_reserve(buf.
size() + n);
412 template <
typename Iterator>
413 constexpr
auto reserve(Iterator& it,
size_t) -> Iterator& {
417 template <
typename OutputIt>
418 using reserve_iterator =
419 remove_reference_t<decltype(reserve(std::declval<OutputIt&>(), 0))>;
421 template <
typename T,
typename OutputIt>
422 constexpr
auto to_pointer(OutputIt,
size_t) -> T* {
425 template <
typename T>
auto to_pointer(buffer_appender<T> it,
size_t n) -> T* {
427 auto size = buf.
size();
428 if (buf.
capacity() < size + n)
return nullptr;
429 buf.try_resize(size + n);
430 return buf.
data() + size;
433 template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
434 inline auto base_iterator(std::back_insert_iterator<Container>& it,
435 checked_ptr<typename Container::value_type>)
436 -> std::back_insert_iterator<Container> {
440 template <
typename Iterator>
441 constexpr
auto base_iterator(Iterator, Iterator it) -> Iterator {
447 template <
typename OutputIt,
typename Size,
typename T>
448 FMT_CONSTEXPR
auto fill_n(OutputIt out, Size count,
const T&
value)
450 for (Size i = 0; i < count; ++i) *out++ = value;
453 template <
typename T,
typename Size>
454 FMT_CONSTEXPR20
auto fill_n(T* out, Size count,
char value) -> T* {
455 if (is_constant_evaluated()) {
456 return fill_n<T*, Size, T>(out, count, value);
458 std::memset(out, value, to_unsigned(count));
463 using char8_type = char8_t;
465 enum char8_type :
unsigned char {};
468 template <
typename OutChar,
typename InputIt,
typename OutputIt>
469 FMT_CONSTEXPR FMT_NOINLINE
auto copy_str_noinline(InputIt begin, InputIt end,
470 OutputIt out) -> OutputIt {
471 return copy_str<OutChar>(begin, end, out);
491 FMT_CONSTEXPR
inline auto utf8_decode(
const char* s, uint32_t* c,
int* e)
493 constexpr
const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
494 constexpr
const uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
495 constexpr
const int shiftc[] = {0, 18, 12, 6, 0};
496 constexpr
const int shifte[] = {0, 6, 4, 2, 0};
498 int len = code_point_length(s);
499 const char* next = s + len;
503 *c = uint32_t(s[0] & masks[len]) << 18;
504 *c |= uint32_t(s[1] & 0x3f) << 12;
505 *c |= uint32_t(s[2] & 0x3f) << 6;
506 *c |= uint32_t(s[3] & 0x3f) << 0;
510 using uchar =
unsigned char;
511 *e = (*c < mins[len]) << 6;
512 *e |= ((*c >> 11) == 0x1b) << 7;
513 *e |= (*c > 0x10FFFF) << 8;
514 *e |= (uchar(s[1]) & 0xc0) >> 2;
515 *e |= (uchar(s[2]) & 0xc0) >> 4;
516 *e |= uchar(s[3]) >> 6;
523 constexpr uint32_t invalid_code_point = ~uint32_t();
527 template <
typename F>
528 FMT_CONSTEXPR
void for_each_codepoint(
string_view s, F f) {
529 auto decode = [f](
const char* buf_ptr,
const char* ptr) {
530 auto cp = uint32_t();
532 auto end = utf8_decode(buf_ptr, &cp, &error);
533 bool result = f(error ? invalid_code_point : cp,
535 return result ? end :
nullptr;
538 const size_t block_size = 4;
539 if (s.
size() >= block_size) {
540 for (
auto end = p + s.
size() - block_size + 1; p < end;) {
545 if (
auto num_chars_left = s.
data() + s.
size() - p) {
546 char buf[2 * block_size - 1] = {};
547 copy_str<char>(p, p + num_chars_left, buf);
548 const char* buf_ptr = buf;
550 auto end = decode(buf_ptr, p);
554 }
while (buf_ptr - buf < num_chars_left);
558 template <
typename Char>
564 FMT_CONSTEXPR
inline size_t compute_width(
string_view s) {
565 size_t num_code_points = 0;
567 struct count_code_points {
569 FMT_CONSTEXPR
auto operator()(uint32_t cp,
string_view)
const ->
bool {
570 *count += detail::to_unsigned(
577 (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) ||
578 (cp >= 0xac00 && cp <= 0xd7a3) ||
579 (cp >= 0xf900 && cp <= 0xfaff) ||
580 (cp >= 0xfe10 && cp <= 0xfe19) ||
581 (cp >= 0xfe30 && cp <= 0xfe6f) ||
582 (cp >= 0xff00 && cp <= 0xff60) ||
583 (cp >= 0xffe0 && cp <= 0xffe6) ||
584 (cp >= 0x20000 && cp <= 0x2fffd) ||
585 (cp >= 0x30000 && cp <= 0x3fffd) ||
587 (cp >= 0x1f300 && cp <= 0x1f64f) ||
589 (cp >= 0x1f900 && cp <= 0x1f9ff))));
593 for_each_codepoint(s, count_code_points{&num_code_points});
594 return num_code_points;
599 reinterpret_cast<const char*>(s.
data()), s.
size()));
602 template <
typename Char>
604 size_t size = s.
size();
605 return n < size ? n : size;
611 const char8_type* data = s.
data();
612 size_t num_code_points = 0;
613 for (
size_t i = 0, size = s.
size(); i != size; ++i) {
614 if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n)
return i;
619 template <typename T, bool = std::is_floating_point<T>::value>
620 struct is_fast_float : bool_constant<std::numeric_limits<T>::is_iec559 &&
621 sizeof(T) <= sizeof(double)> {};
622 template <typename T> struct is_fast_float<T, false> : std::false_type {};
624 #ifndef FMT_USE_FULL_CACHE_DRAGONBOX
625 # define FMT_USE_FULL_CACHE_DRAGONBOX 0
628 template <typename T>
629 template <typename U>
630 void buffer<T>::append(const U* begin, const U* end) {
631 while (begin != end) {
632 auto count = to_unsigned(end - begin);
633 try_reserve(size_ + count);
634 auto free_cap = capacity_ - size_;
635 if (free_cap < count) count = free_cap;
636 std::uninitialized_copy_n(begin, count, make_checked(ptr_ + size_, count));
642 template <typename T, typename Enable = void>
643 struct is_locale : std::false_type {};
644 template <typename T>
645 struct is_locale<T, void_t<decltype(T::classic())>> : std::true_type {};
648 FMT_MODULE_EXPORT_BEGIN
652 enum { inline_buffer_size = 500 };
675 template <typename T, size_t SIZE = inline_buffer_size,
676 typename Allocator = std::allocator<T>>
677 class basic_memory_buffer final : public detail::buffer<T> {
685 FMT_CONSTEXPR20 void deallocate() {
686 T* data = this->data();
687 if (data != store_) alloc_.deallocate(data, this->capacity());
691 FMT_CONSTEXPR20 void grow(size_t size) override;
694 using value_type = T;
695 using const_reference = const T&;
698 const Allocator& alloc = Allocator())
700 this->
set(store_, SIZE);
701 if (detail::is_constant_evaluated()) {
702 detail::fill_n(store_, SIZE, T{});
710 alloc_ = std::move(other.alloc_);
711 T* data = other.data();
712 size_t size = other.size(), capacity = other.capacity();
713 if (data == other.store_) {
714 this->
set(store_, capacity);
715 if (detail::is_constant_evaluated()) {
716 detail::copy_str<T>(other.store_, other.store_ + size,
717 detail::make_checked(store_, capacity));
719 std::uninitialized_copy(other.store_, other.store_ + size,
720 detail::make_checked(store_, capacity));
723 this->
set(data, capacity);
726 other.set(other.store_, 0);
750 FMT_ASSERT(
this != &other,
"");
757 auto get_allocator()
const -> Allocator {
return alloc_; }
763 FMT_CONSTEXPR20
void resize(
size_t count) { this->try_resize(count); }
766 void reserve(
size_t new_capacity) { this->try_reserve(new_capacity); }
769 using detail::buffer<T>::append;
770 template <
typename ContiguousRange>
771 void append(
const ContiguousRange&
range) {
772 append(range.data(), range.data() + range.size());
776 template <
typename T,
size_t SIZE,
typename Allocator>
780 if (size > 5000)
throw std::runtime_error(
"fuzz mode - won't grow that much");
782 const size_t max_size = std::allocator_traits<Allocator>::max_size(alloc_);
783 size_t old_capacity = this->capacity();
784 size_t new_capacity = old_capacity + old_capacity / 2;
785 if (size > new_capacity)
787 else if (new_capacity > max_size)
788 new_capacity = size > max_size ? size : max_size;
789 T* old_data = this->data();
791 std::allocator_traits<Allocator>::allocate(alloc_, new_capacity);
793 std::uninitialized_copy(old_data, old_data + this->size(),
794 detail::make_checked(new_data, new_capacity));
795 this->
set(new_data, new_capacity);
799 if (old_data != store_) alloc_.deallocate(old_data, old_capacity);
804 template <
typename T,
size_t SIZE,
typename Allocator>
816 explicit format_error(
const char* message) : std::runtime_error(message) {}
818 : std::runtime_error(message) {}
834 template <
typename... Args,
typename S,
typename Char = char_t<S>>
835 FMT_INLINE
auto make_args_checked(
const S&
fmt,
836 const remove_reference_t<Args>&... args)
840 std::is_base_of<detail::view, remove_reference_t<Args>>::
value &&
841 std::is_reference<Args>::value)...>() == 0,
842 "passing views as lvalues is disallowed");
843 detail::check_format_string<Args...>(fmt);
849 #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 850 template <
typename Char,
size_t N>
struct fixed_string {
851 constexpr fixed_string(
const Char (&str)[N]) {
852 detail::copy_str<Char, const Char*, Char*>(
static_cast<const Char*
>(str),
860 template <
typename Char,
size_t N>
861 constexpr
auto compile_string_to_view(
const Char (&s)[N])
865 return {s, N - (std::char_traits<Char>::to_int_type(s[N - 1]) == 0 ? 1 : 0)};
867 template <
typename Char>
868 constexpr
auto compile_string_to_view(detail::std_string_view<Char> s)
870 return {s.
data(), s.size()};
874 FMT_BEGIN_DETAIL_NAMESPACE
876 template <
typename T>
struct is_integral : std::is_integral<T> {};
880 template <
typename T>
882 std::integral_constant<bool, std::numeric_limits<T>::is_signed ||
883 std::is_same<T, int128_t>::value>;
887 template <typename T, FMT_ENABLE_IF(is_signed<T>::value)>
888 FMT_CONSTEXPR
auto is_negative(T
value) ->
bool {
891 template <typename T, FMT_ENABLE_IF(!is_signed<T>::value)>
892 FMT_CONSTEXPR
auto is_negative(T) ->
bool {
896 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
897 FMT_CONSTEXPR
auto is_supported_floating_point(T) -> uint16_t {
898 return (std::is_same<T, float>::value && FMT_USE_FLOAT) ||
899 (std::is_same<T, double>::value && FMT_USE_DOUBLE) ||
900 (std::is_same<T, long double>::value && FMT_USE_LONG_DOUBLE);
905 template <
typename T>
906 using uint32_or_64_or_128_t =
907 conditional_t<num_bits<T>() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS,
909 conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>;
910 template <
typename T>
911 using uint64_or_128_t = conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>;
913 #define FMT_POWERS_OF_10(factor) \ 914 factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \ 915 (factor)*1000000, (factor)*10000000, (factor)*100000000, \ 919 constexpr
const char* digits2(
size_t value) {
921 return &
"0001020304050607080910111213141516171819" 922 "2021222324252627282930313233343536373839" 923 "4041424344454647484950515253545556575859" 924 "6061626364656667686970717273747576777879" 925 "8081828384858687888990919293949596979899"[value * 2];
929 template <
typename Char,
typename Sign> constexpr Char
sign(Sign s) {
930 #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604 931 static_assert(std::is_same<Sign, sign_t>::value,
"");
933 return static_cast<Char
>(
"\0-+ "[s]);
936 template <
typename T> FMT_CONSTEXPR
auto count_digits_fallback(T n) ->
int {
942 if (n < 10)
return count;
943 if (n < 100)
return count + 1;
944 if (n < 1000)
return count + 2;
945 if (n < 10000)
return count + 3;
951 FMT_CONSTEXPR
inline auto count_digits(uint128_t n) ->
int {
952 return count_digits_fallback(n);
956 #ifdef FMT_BUILTIN_CLZLL 959 inline auto do_count_digits(uint64_t n) ->
int {
964 static constexpr uint8_t bsr2log10[] = {
965 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
966 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
967 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
968 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20};
969 auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63];
970 static constexpr
const uint64_t zero_or_powers_of_10[] = {
971 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL),
972 10000000000000000000ULL};
973 return t - (n < zero_or_powers_of_10[t]);
979 FMT_CONSTEXPR20
inline auto count_digits(uint64_t n) ->
int {
980 #ifdef FMT_BUILTIN_CLZLL 981 if (!is_constant_evaluated()) {
982 return do_count_digits(n);
985 return count_digits_fallback(n);
989 template <
int BITS,
typename UInt>
990 FMT_CONSTEXPR
auto count_digits(UInt n) ->
int {
991 #ifdef FMT_BUILTIN_CLZ 992 if (num_bits<UInt>() == 32)
993 return (FMT_BUILTIN_CLZ(static_cast<uint32_t>(n) | 1) ^ 31) / BITS + 1;
1000 }
while ((m >>= BITS) != 0);
1007 #ifdef FMT_BUILTIN_CLZ 1010 FMT_INLINE
auto do_count_digits(uint32_t n) ->
int {
1013 # define FMT_INC(T) (((sizeof(# T) - 1ull) << 32) - T) 1014 static constexpr uint64_t table[] = {
1015 FMT_INC(0), FMT_INC(0), FMT_INC(0),
1016 FMT_INC(10), FMT_INC(10), FMT_INC(10),
1017 FMT_INC(100), FMT_INC(100), FMT_INC(100),
1018 FMT_INC(1000), FMT_INC(1000), FMT_INC(1000),
1019 FMT_INC(10000), FMT_INC(10000), FMT_INC(10000),
1020 FMT_INC(100000), FMT_INC(100000), FMT_INC(100000),
1021 FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000),
1022 FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000),
1023 FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000),
1024 FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000),
1025 FMT_INC(1000000000), FMT_INC(1000000000)
1027 auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31];
1028 return static_cast<int>((n + inc) >> 32);
1033 FMT_CONSTEXPR20
inline auto count_digits(uint32_t n) ->
int {
1034 #ifdef FMT_BUILTIN_CLZ 1035 if (!is_constant_evaluated()) {
1036 return do_count_digits(n);
1039 return count_digits_fallback(n);
1042 template <
typename Int> constexpr
auto digits10() FMT_NOEXCEPT ->
int {
1043 return std::numeric_limits<Int>::digits10;
1045 template <> constexpr
auto digits10<int128_t>() FMT_NOEXCEPT ->
int {
1048 template <> constexpr
auto digits10<uint128_t>() FMT_NOEXCEPT ->
int {
1053 std::string grouping;
1057 template <
typename Char>
1059 template <
typename Char>
1061 auto result = thousands_sep_impl<char>(loc);
1062 return {result.grouping, Char(result.thousands_sep)};
1066 return thousands_sep_impl<wchar_t>(loc);
1069 template <
typename Char>
1070 FMT_API
auto decimal_point_impl(
locale_ref loc) -> Char;
1071 template <
typename Char>
inline auto decimal_point(
locale_ref loc) -> Char {
1072 return Char(decimal_point_impl<char>(loc));
1074 template <>
inline auto decimal_point(
locale_ref loc) ->
wchar_t {
1075 return decimal_point_impl<wchar_t>(loc);
1079 template <
typename Char>
auto equal2(
const Char* lhs,
const char* rhs) ->
bool {
1080 return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]);
1082 inline auto equal2(
const char* lhs,
const char* rhs) ->
bool {
1083 return memcmp(lhs, rhs, 2) == 0;
1087 template <
typename Char>
1088 FMT_CONSTEXPR20 FMT_INLINE
void copy2(Char* dst,
const char* src) {
1089 if (!is_constant_evaluated() &&
sizeof(Char) ==
sizeof(
char)) {
1090 memcpy(dst, src, 2);
1093 *dst++ =
static_cast<Char
>(*src++);
1094 *dst =
static_cast<Char
>(*src);
1105 template <
typename Char,
typename UInt>
1106 FMT_CONSTEXPR20
auto format_decimal(Char* out, UInt value,
int size)
1108 FMT_ASSERT(size >= count_digits(value),
"invalid digit count");
1111 while (value >= 100) {
1116 copy2(out, digits2(static_cast<size_t>(value % 100)));
1120 *--out =
static_cast<Char
>(
'0' + value);
1124 copy2(out, digits2(static_cast<size_t>(value)));
1128 template <
typename Char,
typename UInt,
typename Iterator,
1129 FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<Iterator>>::value)>
1130 inline auto format_decimal(Iterator out, UInt value,
int size)
1133 Char
buffer[digits10<UInt>() + 1];
1134 auto end = format_decimal(
buffer, value, size).end;
1135 return {out, detail::copy_str_noinline<Char>(
buffer, end, out)};
1138 template <
unsigned BASE_BITS,
typename Char,
typename UInt>
1139 FMT_CONSTEXPR
auto format_uint(Char*
buffer, UInt value,
int num_digits,
1140 bool upper =
false) -> Char* {
1141 buffer += num_digits;
1144 const char* digits = upper ?
"0123456789ABCDEF" :
"0123456789abcdef";
1145 unsigned digit = (value & ((1 << BASE_BITS) - 1));
1146 *--buffer =
static_cast<Char
>(BASE_BITS < 4 ? static_cast<char>(
'0' + digit)
1148 }
while ((value >>= BASE_BITS) != 0);
1152 template <
unsigned BASE_BITS,
typename Char>
1154 bool =
false) -> Char* {
1155 auto char_digits = std::numeric_limits<unsigned char>::digits / 4;
1156 int start = (num_digits + char_digits - 1) / char_digits - 1;
1157 if (
int start_digits = num_digits % char_digits) {
1158 unsigned value = n.value[start--];
1159 buffer = format_uint<BASE_BITS>(buffer, value, start_digits);
1161 for (; start >= 0; --start) {
1162 unsigned value = n.value[start];
1163 buffer += char_digits;
1165 for (
int i = 0; i < char_digits; ++i) {
1166 unsigned digit = (value & ((1 << BASE_BITS) - 1));
1167 *--p =
static_cast<Char
>(
"0123456789abcdef"[digit]);
1168 value >>= BASE_BITS;
1174 template <
unsigned BASE_BITS,
typename Char,
typename It,
typename UInt>
1175 inline auto format_uint(It out, UInt value,
int num_digits,
bool upper =
false)
1177 if (
auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
1178 format_uint<BASE_BITS>(ptr, value, num_digits, upper);
1182 char buffer[num_bits<UInt>() / BASE_BITS + 1];
1183 format_uint<BASE_BITS>(buffer, value, num_digits, upper);
1184 return detail::copy_str_noinline<Char>(buffer, buffer + num_digits, out);
1195 auto size()
const ->
size_t {
return buffer_.size() - 1; }
1196 auto c_str()
const ->
const wchar_t* {
return &buffer_[0]; }
1197 auto str()
const -> std::wstring {
return {&buffer_[0], size()}; }
1206 using carrier_uint = uint32_t;
1207 static const int significand_bits = 23;
1208 static const int exponent_bits = 8;
1209 static const int min_exponent = -126;
1210 static const int max_exponent = 127;
1211 static const int exponent_bias = -127;
1212 static const int decimal_digits = 9;
1213 static const int kappa = 1;
1214 static const int big_divisor = 100;
1215 static const int small_divisor = 10;
1216 static const int min_k = -31;
1217 static const int max_k = 46;
1218 static const int cache_bits = 64;
1219 static const int divisibility_check_by_5_threshold = 39;
1220 static const int case_fc_pm_half_lower_threshold = -1;
1221 static const int case_fc_pm_half_upper_threshold = 6;
1222 static const int case_fc_lower_threshold = -2;
1223 static const int case_fc_upper_threshold = 6;
1224 static const int case_shorter_interval_left_endpoint_lower_threshold = 2;
1225 static const int case_shorter_interval_left_endpoint_upper_threshold = 3;
1226 static const int shorter_interval_tie_lower_threshold = -35;
1227 static const int shorter_interval_tie_upper_threshold = -35;
1228 static const int max_trailing_zeros = 7;
1232 using carrier_uint = uint64_t;
1233 static const int significand_bits = 52;
1234 static const int exponent_bits = 11;
1235 static const int min_exponent = -1022;
1236 static const int max_exponent = 1023;
1237 static const int exponent_bias = -1023;
1238 static const int decimal_digits = 17;
1239 static const int kappa = 2;
1240 static const int big_divisor = 1000;
1241 static const int small_divisor = 100;
1242 static const int min_k = -292;
1243 static const int max_k = 326;
1244 static const int cache_bits = 128;
1245 static const int divisibility_check_by_5_threshold = 86;
1246 static const int case_fc_pm_half_lower_threshold = -2;
1247 static const int case_fc_pm_half_upper_threshold = 9;
1248 static const int case_fc_lower_threshold = -4;
1249 static const int case_fc_upper_threshold = 9;
1250 static const int case_shorter_interval_left_endpoint_lower_threshold = 2;
1251 static const int case_shorter_interval_left_endpoint_upper_threshold = 3;
1252 static const int shorter_interval_tie_lower_threshold = -77;
1253 static const int shorter_interval_tie_upper_threshold = -77;
1254 static const int max_trailing_zeros = 16;
1259 significand_type significand;
1263 template <
typename T>
1267 template <
typename T>
1268 constexpr
auto exponent_mask() ->
1276 template <
typename Char,
typename It>
1277 FMT_CONSTEXPR
auto write_exponent(
int exp, It it) -> It {
1278 FMT_ASSERT(-10000 < exp && exp < 10000,
"exponent out of range");
1280 *it++ =
static_cast<Char
>(
'-');
1283 *it++ =
static_cast<Char
>(
'+');
1286 const char* top = digits2(to_unsigned(exp / 100));
1287 if (exp >= 1000) *it++ =
static_cast<Char
>(top[0]);
1288 *it++ =
static_cast<Char
>(top[1]);
1291 const char* d = digits2(to_unsigned(exp));
1292 *it++ =
static_cast<Char
>(d[0]);
1293 *it++ =
static_cast<Char
>(d[1]);
1297 template <
typename T>
1298 FMT_HEADER_ONLY_CONSTEXPR20
auto format_float(T value,
int precision,
1303 template <
typename T>
1304 auto snprintf_float(T value,
int precision,
float_specs specs,
1307 template <
typename T> constexpr
auto promote_float(T value) -> T {
1310 constexpr
auto promote_float(
float value) ->
double {
1311 return static_cast<double>(value);
1314 template <
typename OutputIt,
typename Char>
1315 FMT_NOINLINE FMT_CONSTEXPR
auto fill(OutputIt it,
size_t n,
1317 auto fill_size = fill.size();
1318 if (fill_size == 1)
return detail::fill_n(it, n, fill[0]);
1319 auto data = fill.data();
1320 for (
size_t i = 0; i < n; ++i)
1321 it = copy_str<Char>(data, data + fill_size, it);
1328 template <align::type
align = align::left,
typename OutputIt,
typename Char,
1330 FMT_CONSTEXPR
auto write_padded(OutputIt out,
1332 size_t size,
size_t width, F&& f) -> OutputIt {
1333 static_assert(align == align::left || align == align::right,
"");
1334 unsigned spec_width = to_unsigned(specs.width);
1335 size_t padding = spec_width > width ? spec_width - width : 0;
1338 auto* shifts = align == align::left ?
"\x1f\x1f\x00\x01" :
"\x00\x1f\x00\x01";
1339 size_t left_padding = padding >> shifts[specs.align];
1340 size_t right_padding = padding - left_padding;
1341 auto it = reserve(out, size + padding * specs.fill.size());
1342 if (left_padding != 0) it = fill(it, left_padding, specs.fill);
1344 if (right_padding != 0) it = fill(it, right_padding, specs.fill);
1345 return base_iterator(out, it);
1348 template <align::type align = align::left,
typename OutputIt,
typename Char,
1351 size_t size, F&& f) -> OutputIt {
1352 return write_padded<align>(out, specs, size, size, f);
1355 template <align::type align = align::left,
typename Char,
typename OutputIt>
1359 return write_padded<align>(
1360 out, specs, bytes.
size(), [bytes](reserve_iterator<OutputIt> it) {
1361 const char* data = bytes.
data();
1362 return copy_str<Char>(data, data + bytes.
size(), it);
1366 template <
typename Char,
typename OutputIt,
typename UIntPtr>
1367 auto write_ptr(OutputIt out, UIntPtr value,
1369 int num_digits = count_digits<4>(value);
1370 auto size = to_unsigned(num_digits) + size_t(2);
1371 auto write = [=](reserve_iterator<OutputIt> it) {
1372 *it++ =
static_cast<Char
>(
'0');
1373 *it++ =
static_cast<Char
>(
'x');
1374 return format_uint<4, Char>(it, value, num_digits);
1376 return specs ? write_padded<align::right>(out, *specs, size, write)
1377 : base_iterator(out, write(reserve(out, size)));
1380 template <
typename Char,
typename OutputIt>
1381 FMT_CONSTEXPR
auto write_char(OutputIt out, Char value,
1384 return write_padded(out, specs, 1, [=](reserve_iterator<OutputIt> it) {
1389 template <
typename Char,
typename OutputIt>
1390 FMT_CONSTEXPR
auto write(OutputIt out, Char value,
1393 return check_char_specs(specs)
1394 ? write_char(out, value, specs)
1395 : write(out, static_cast<int>(value), specs, loc);
1406 : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) {
1407 if (specs.align == align::numeric) {
1408 auto width = to_unsigned(specs.width);
1410 padding = width - size;
1413 }
else if (specs.precision > num_digits) {
1414 size = (prefix >> 24) + to_unsigned(specs.precision);
1415 padding = to_unsigned(specs.precision - num_digits);
1424 template <
typename OutputIt,
typename Char,
typename W>
1425 FMT_CONSTEXPR FMT_INLINE
auto write_int(OutputIt out,
int num_digits,
1428 W write_digits) -> OutputIt {
1430 if ((specs.width | (specs.precision + 1)) == 0) {
1431 auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24));
1433 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
1434 *it++ = static_cast<Char>(p & 0xff);
1436 return base_iterator(out, write_digits(it));
1439 return write_padded<align::right>(
1440 out, specs, data.size, [=](reserve_iterator<OutputIt> it) {
1441 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
1442 *it++ = static_cast<Char>(p & 0xff);
1443 it = detail::fill_n(it, data.padding, static_cast<Char>(
'0'));
1444 return write_digits(it);
1453 std::string::const_iterator group;
1456 next_state initial_state()
const {
return {sep_.grouping.begin(), 0}; }
1459 int next(next_state& state)
const {
1460 if (!sep_.thousands_sep)
return max_value<int>();
1461 if (state.group == sep_.grouping.end())
1462 return state.pos += sep_.grouping.back();
1463 if (*state.group <= 0 || *state.group == max_value<char>())
1464 return max_value<int>();
1465 state.pos += *state.group++;
1472 sep_ = thousands_sep<Char>(loc);
1474 sep_.thousands_sep = Char();
1478 Char separator()
const {
return sep_.thousands_sep; }
1480 int count_separators(
int num_digits)
const {
1482 auto state = initial_state();
1483 while (num_digits > next(state)) ++count;
1488 template <
typename Out,
typename C>
1490 auto num_digits =
static_cast<int>(digits.
size());
1492 separators.push_back(0);
1493 auto state = initial_state();
1494 while (
int i = next(state)) {
1495 if (i >= num_digits)
break;
1496 separators.push_back(i);
1498 for (
int i = 0, sep_index = static_cast<int>(separators.size() - 1);
1499 i < num_digits; ++i) {
1500 if (num_digits - i == separators[sep_index]) {
1501 *out++ = separator();
1504 *out++ =
static_cast<Char
>(digits[to_unsigned(i)]);
1510 template <
typename OutputIt,
typename UInt,
typename Char>
1511 auto write_int_localized(OutputIt out, UInt value,
unsigned prefix,
1514 static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value,
"");
1515 int num_digits = count_digits(value);
1517 format_decimal(digits, value, num_digits);
1518 unsigned size = to_unsigned((prefix != 0 ? 1 : 0) + num_digits +
1519 grouping.count_separators(num_digits));
1520 return write_padded<align::right>(
1521 out, specs, size, size, [&](reserve_iterator<OutputIt> it) {
1522 if (prefix != 0) *it++ =
static_cast<Char
>(prefix);
1523 return grouping.apply(it,
string_view(digits, to_unsigned(num_digits)));
1527 template <
typename OutputIt,
typename UInt,
typename Char>
1528 auto write_int_localized(OutputIt& out, UInt value,
unsigned prefix,
1532 out = write_int_localized(out, value, prefix, specs, grouping);
1536 FMT_CONSTEXPR
inline void prefix_append(
unsigned& prefix,
unsigned value) {
1537 prefix |= prefix != 0 ? value << 8 : value;
1538 prefix += (1u + (value > 0xff ? 1 : 0)) << 24;
1546 template <
typename T>
1547 FMT_CONSTEXPR
auto make_write_int_arg(T value, sign_t
sign)
1550 auto abs_value =
static_cast<uint32_or_64_or_128_t<T>
>(value);
1551 if (is_negative(value)) {
1552 prefix = 0x01000000 |
'-';
1553 abs_value = 0 - abs_value;
1555 constexpr
const unsigned prefixes[4] = {0, 0, 0x1000000u |
'+',
1557 prefix = prefixes[sign];
1559 return {abs_value, prefix};
1562 template <
typename Char,
typename OutputIt,
typename T>
1563 FMT_CONSTEXPR FMT_INLINE
auto write_int(OutputIt out,
write_int_arg<T> arg,
1566 static_assert(std::is_same<T, uint32_or_64_or_128_t<T>>::value,
"");
1567 auto abs_value = arg.abs_value;
1568 auto prefix = arg.prefix;
1569 switch (specs.type) {
1570 case presentation_type::none:
1571 case presentation_type::dec: {
1572 if (specs.localized &&
1573 write_int_localized(out,
static_cast<uint64_or_128_t<T>
>(abs_value),
1574 prefix, specs, loc)) {
1577 auto num_digits = count_digits(abs_value);
1579 out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
1580 return format_decimal<Char>(it, abs_value, num_digits).end;
1583 case presentation_type::hex_lower:
1584 case presentation_type::hex_upper: {
1585 bool upper = specs.type == presentation_type::hex_upper;
1587 prefix_append(prefix,
unsigned(upper ?
'X' :
'x') << 8 |
'0');
1588 int num_digits = count_digits<4>(abs_value);
1590 out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
1591 return format_uint<4, Char>(it, abs_value, num_digits, upper);
1594 case presentation_type::bin_lower:
1595 case presentation_type::bin_upper: {
1596 bool upper = specs.type == presentation_type::bin_upper;
1598 prefix_append(prefix,
unsigned(upper ?
'B' :
'b') << 8 |
'0');
1599 int num_digits = count_digits<1>(abs_value);
1600 return write_int(out, num_digits, prefix, specs,
1601 [=](reserve_iterator<OutputIt> it) {
1602 return format_uint<1, Char>(it, abs_value, num_digits);
1605 case presentation_type::oct: {
1606 int num_digits = count_digits<3>(abs_value);
1609 if (specs.alt && specs.precision <= num_digits && abs_value != 0)
1610 prefix_append(prefix,
'0');
1611 return write_int(out, num_digits, prefix, specs,
1612 [=](reserve_iterator<OutputIt> it) {
1613 return format_uint<3, Char>(it, abs_value, num_digits);
1616 case presentation_type::chr:
1617 return write_char(out, static_cast<Char>(abs_value), specs);
1619 throw_format_error(
"invalid type specifier");
1623 template <
typename Char,
typename OutputIt,
typename T>
1624 FMT_CONSTEXPR FMT_NOINLINE
auto write_int_noinline(
1627 return write_int(out, arg, specs, loc);
1629 template <
typename Char,
typename OutputIt,
typename T,
1631 !std::is_same<T, bool>::value &&
1632 std::is_same<OutputIt, buffer_appender<Char>>::value)>
1633 FMT_CONSTEXPR FMT_INLINE
auto write(OutputIt out, T value,
1636 return write_int_noinline(out, make_write_int_arg(value, specs.sign), specs,
1640 template <
typename Char,
typename OutputIt,
typename T,
1642 !std::is_same<T, bool>::value &&
1643 !std::is_same<OutputIt, buffer_appender<Char>>::value)>
1644 FMT_CONSTEXPR FMT_INLINE
auto write(OutputIt out, T value,
1647 return write_int(out, make_write_int_arg(value, specs.sign), specs, loc);
1650 template <
typename Char,
typename OutputIt>
1653 auto data = s.
data();
1654 auto size = s.
size();
1655 if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
1656 size = code_point_index(s, to_unsigned(specs.precision));
1659 return write_padded(out, specs, size, width,
1660 [=](reserve_iterator<OutputIt> it) {
1661 return copy_str<Char>(data, data + size, it);
1664 template <
typename Char,
typename OutputIt>
1665 FMT_CONSTEXPR
auto write(OutputIt out,
1669 check_string_type_spec(specs.type);
1670 return write(out, s, specs);
1672 template <
typename Char,
typename OutputIt>
1673 FMT_CONSTEXPR
auto write(OutputIt out,
const Char* s,
1676 return check_cstring_type_spec(specs.type)
1678 : write_ptr<Char>(out, to_uintptr(s), &specs);
1681 template <
typename Char,
typename OutputIt>
1682 FMT_CONSTEXPR20
auto write_nonfinite(OutputIt out,
bool isinf,
1686 isinf ? (fspecs.upper ?
"INF" :
"inf") : (fspecs.upper ?
"NAN" :
"nan");
1687 constexpr
size_t str_size = 3;
1688 auto sign = fspecs.sign;
1689 auto size = str_size + (sign ? 1 : 0);
1691 const bool is_zero_fill =
1692 specs.fill.size() == 1 && *specs.fill.data() ==
static_cast<Char
>(
'0');
1693 if (is_zero_fill) specs.fill[0] =
static_cast<Char
>(
' ');
1694 return write_padded(out, specs, size, [=](reserve_iterator<OutputIt> it) {
1695 if (sign) *it++ = detail::sign<Char>(sign);
1696 return copy_str<Char>(str, str + str_size, it);
1702 const char* significand;
1703 int significand_size;
1707 constexpr
auto get_significand_size(
const big_decimal_fp& fp) ->
int {
1708 return fp.significand_size;
1710 template <
typename T>
1712 return count_digits(fp.significand);
1715 template <
typename Char,
typename OutputIt>
1716 constexpr
auto write_significand(OutputIt out,
const char* significand,
1717 int significand_size) -> OutputIt {
1718 return copy_str<Char>(significand, significand + significand_size, out);
1720 template <
typename Char,
typename OutputIt,
typename UInt>
1721 inline auto write_significand(OutputIt out, UInt significand,
1722 int significand_size) -> OutputIt {
1723 return format_decimal<Char>(out, significand, significand_size).end;
1725 template <
typename Char,
typename OutputIt,
typename T,
typename Grouping>
1726 FMT_CONSTEXPR20
auto write_significand(OutputIt out, T significand,
1727 int significand_size,
int exponent,
1728 const Grouping& grouping) -> OutputIt {
1729 if (!grouping.separator()) {
1730 out = write_significand<Char>(out, significand, significand_size);
1731 return detail::fill_n(out, exponent, static_cast<Char>(
'0'));
1734 write_significand<char>(
appender(buffer), significand, significand_size);
1735 detail::fill_n(
appender(buffer), exponent,
'0');
1736 return grouping.apply(out,
string_view(buffer.data(), buffer.size()));
1739 template <
typename Char,
typename UInt,
1740 FMT_ENABLE_IF(std::is_integral<UInt>::value)>
1741 inline auto write_significand(Char* out, UInt significand,
int significand_size,
1742 int integral_size, Char decimal_point) -> Char* {
1744 return format_decimal(out, significand, significand_size).end;
1745 out += significand_size + 1;
1747 int floating_size = significand_size - integral_size;
1748 for (
int i = floating_size / 2; i > 0; --i) {
1750 copy2(out, digits2(significand % 100));
1753 if (floating_size % 2 != 0) {
1754 *--out =
static_cast<Char
>(
'0' + significand % 10);
1757 *--out = decimal_point;
1758 format_decimal(out - integral_size, significand, integral_size);
1762 template <
typename OutputIt,
typename UInt,
typename Char,
1763 FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)>
1764 inline auto write_significand(OutputIt out, UInt significand,
1765 int significand_size,
int integral_size,
1766 Char decimal_point) -> OutputIt {
1768 Char buffer[digits10<UInt>() + 2];
1769 auto end = write_significand(buffer, significand, significand_size,
1770 integral_size, decimal_point);
1771 return detail::copy_str_noinline<Char>(buffer, end, out);
1774 template <
typename OutputIt,
typename Char>
1775 FMT_CONSTEXPR
auto write_significand(OutputIt out,
const char* significand,
1776 int significand_size,
int integral_size,
1777 Char decimal_point) -> OutputIt {
1778 out = detail::copy_str_noinline<Char>(significand,
1779 significand + integral_size, out);
1780 if (!decimal_point)
return out;
1781 *out++ = decimal_point;
1782 return detail::copy_str_noinline<Char>(significand + integral_size,
1783 significand + significand_size, out);
1786 template <
typename OutputIt,
typename Char,
typename T,
typename Grouping>
1787 FMT_CONSTEXPR20
auto write_significand(OutputIt out, T significand,
1788 int significand_size,
int integral_size,
1790 const Grouping& grouping) -> OutputIt {
1791 if (!grouping.separator()) {
1792 return write_significand(out, significand, significand_size, integral_size,
1796 write_significand(buffer_appender<Char>(buffer), significand,
1797 significand_size, integral_size, decimal_point);
1800 return detail::copy_str_noinline<Char>(buffer.data() + integral_size,
1804 template <
typename OutputIt,
typename DecimalFP,
typename Char,
1806 FMT_CONSTEXPR20
auto do_write_float(OutputIt out,
const DecimalFP& fp,
1810 auto significand = fp.significand;
1811 int significand_size = get_significand_size(fp);
1812 constexpr Char zero =
static_cast<Char
>(
'0');
1813 auto sign = fspecs.sign;
1814 size_t size = to_unsigned(significand_size) + (sign ? 1 : 0);
1815 using iterator = reserve_iterator<OutputIt>;
1817 Char decimal_point =
1818 fspecs.locale ? detail::decimal_point<Char>(loc) : static_cast<Char>(
'.');
1820 int output_exp = fp.exponent + significand_size - 1;
1821 auto use_exp_format = [=]() {
1822 if (fspecs.format == float_format::exp)
return true;
1823 if (fspecs.format != float_format::general)
return false;
1826 const int exp_lower = -4, exp_upper = 16;
1827 return output_exp < exp_lower ||
1828 output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper);
1830 if (use_exp_format()) {
1832 if (fspecs.showpoint) {
1833 num_zeros = fspecs.precision - significand_size;
1834 if (num_zeros < 0) num_zeros = 0;
1835 size += to_unsigned(num_zeros);
1836 }
else if (significand_size == 1) {
1837 decimal_point = Char();
1839 auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp;
1841 if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3;
1843 size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits);
1844 char exp_char = fspecs.upper ?
'E' :
'e';
1845 auto write = [=](iterator it) {
1846 if (sign) *it++ = detail::sign<Char>(sign);
1848 it = write_significand(it, significand, significand_size, 1,
1850 if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero);
1851 *it++ =
static_cast<Char
>(exp_char);
1852 return write_exponent<Char>(output_exp, it);
1854 return specs.width > 0 ? write_padded<align::right>(out, specs, size, write)
1855 : base_iterator(out, write(reserve(out, size)));
1858 int exp = fp.exponent + significand_size;
1859 if (fp.exponent >= 0) {
1861 size += to_unsigned(fp.exponent);
1862 int num_zeros = fspecs.precision - exp;
1864 if (num_zeros > 5000)
1865 throw std::runtime_error(
"fuzz mode - avoiding excessive cpu use");
1867 if (fspecs.showpoint) {
1868 if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 1;
1869 if (num_zeros > 0) size += to_unsigned(num_zeros) + 1;
1871 auto grouping = Grouping(loc, fspecs.locale);
1872 size += to_unsigned(grouping.count_separators(significand_size));
1873 return write_padded<align::right>(out, specs, size, [&](iterator it) {
1874 if (sign) *it++ = detail::sign<Char>(sign);
1875 it = write_significand<Char>(it, significand, significand_size,
1876 fp.exponent, grouping);
1877 if (!fspecs.showpoint)
return it;
1878 *it++ = decimal_point;
1879 return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
1881 }
else if (exp > 0) {
1883 int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0;
1884 size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0);
1885 auto grouping = Grouping(loc, fspecs.locale);
1886 size += to_unsigned(grouping.count_separators(significand_size));
1887 return write_padded<align::right>(out, specs, size, [&](iterator it) {
1888 if (sign) *it++ = detail::sign<Char>(sign);
1889 it = write_significand(it, significand, significand_size, exp,
1890 decimal_point, grouping);
1891 return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
1895 int num_zeros = -exp;
1896 if (significand_size == 0 && fspecs.precision >= 0 &&
1897 fspecs.precision < num_zeros) {
1898 num_zeros = fspecs.precision;
1900 bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint;
1901 size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros);
1902 return write_padded<align::right>(out, specs, size, [&](iterator it) {
1903 if (sign) *it++ = detail::sign<Char>(sign);
1905 if (!pointy)
return it;
1906 *it++ = decimal_point;
1907 it = detail::fill_n(it, num_zeros, zero);
1908 return write_significand<Char>(it, significand, significand_size);
1916 constexpr Char separator()
const {
return Char(); }
1918 constexpr
int count_separators(
int)
const {
return 0; }
1920 template <
typename Out,
typename C>
1926 template <
typename OutputIt,
typename DecimalFP,
typename Char>
1927 FMT_CONSTEXPR20
auto write_float(OutputIt out,
const DecimalFP& fp,
1931 if (is_constant_evaluated()) {
1932 return do_write_float<OutputIt, DecimalFP, Char,
1936 return do_write_float(out, fp, specs, fspecs, loc);
1940 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
1941 FMT_CONSTEXPR20
bool isinf(T value) {
1942 if (is_constant_evaluated()) {
1943 #if defined(__cpp_if_constexpr) 1944 if constexpr (std::numeric_limits<double>::is_iec559) {
1945 auto bits = detail::bit_cast<uint64_t>(
static_cast<double>(value));
1946 constexpr
auto significand_bits =
1948 return (bits & exponent_mask<double>()) &&
1949 !(bits & ((uint64_t(1) << significand_bits) - 1));
1953 return std::isinf(value);
1956 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
1957 FMT_CONSTEXPR20
bool isfinite(T value) {
1958 if (is_constant_evaluated()) {
1959 #if defined(__cpp_if_constexpr) 1960 if constexpr (std::numeric_limits<double>::is_iec559) {
1961 auto bits = detail::bit_cast<uint64_t>(
static_cast<double>(value));
1962 return (bits & exponent_mask<double>()) != exponent_mask<double>();
1966 return std::isfinite(value);
1969 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
1970 FMT_INLINE FMT_CONSTEXPR
bool signbit(T value) {
1971 if (is_constant_evaluated()) {
1972 #ifdef __cpp_if_constexpr 1973 if constexpr (std::numeric_limits<double>::is_iec559) {
1974 auto bits = detail::bit_cast<uint64_t>(
static_cast<double>(value));
1975 return (bits & (uint64_t(1) << (num_bits<uint64_t>() - 1))) != 0;
1979 return std::signbit(value);
1982 template <
typename Char,
typename OutputIt,
typename T,
1983 FMT_ENABLE_IF(std::is_floating_point<T>::value)>
1984 FMT_CONSTEXPR20
auto write(OutputIt out, T value,
1987 if (const_check(!is_supported_floating_point(value)))
return out;
1988 float_specs fspecs = parse_float_type_spec(specs);
1989 fspecs.sign = specs.sign;
1990 if (detail::signbit(value)) {
1991 fspecs.sign = sign::minus;
1993 }
else if (fspecs.sign == sign::minus) {
1994 fspecs.sign = sign::none;
1997 if (!detail::isfinite(value))
1998 return write_nonfinite(out, detail::isinf(value), specs, fspecs);
2000 if (specs.align == align::numeric && fspecs.sign) {
2001 auto it = reserve(out, 1);
2002 *it++ = detail::sign<Char>(fspecs.sign);
2003 out = base_iterator(out, it);
2004 fspecs.sign = sign::none;
2005 if (specs.width != 0) --specs.width;
2009 if (fspecs.format == float_format::hex) {
2010 if (fspecs.sign) buffer.push_back(detail::sign<char>(fspecs.sign));
2011 snprintf_float(promote_float(value), specs.precision, fspecs, buffer);
2012 return write_bytes<align::right>(out, {buffer.data(), buffer.size()},
2015 int precision = specs.precision >= 0 || specs.type == presentation_type::none
2018 if (fspecs.format == float_format::exp) {
2019 if (precision == max_value<int>())
2020 throw_format_error(
"number is too big");
2024 if (const_check(std::is_same<T, float>())) fspecs.binary32 =
true;
2025 if (!is_fast_float<T>()) fspecs.fallback =
true;
2026 int exp = format_float(promote_float(value), precision, fspecs, buffer);
2027 fspecs.precision = precision;
2028 auto fp =
big_decimal_fp{buffer.data(),
static_cast<int>(buffer.size()), exp};
2029 return write_float(out, fp, specs, fspecs, loc);
2032 template <
typename Char,
typename OutputIt,
typename T,
2033 FMT_ENABLE_IF(is_fast_float<T>::value)>
2034 FMT_CONSTEXPR20
auto write(OutputIt out, T value) -> OutputIt {
2035 if (is_constant_evaluated()) {
2039 if (const_check(!is_supported_floating_point(value)))
return out;
2041 using floaty = conditional_t<std::is_same<T, long double>::value, double, T>;
2043 auto bits = bit_cast<uint>(value);
2046 if (detail::signbit(value)) {
2047 fspecs.sign = sign::minus;
2052 uint mask = exponent_mask<floaty>();
2053 if ((bits & mask) == mask)
2054 return write_nonfinite(out, std::isinf(value), specs, fspecs);
2056 auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
2057 return write_float(out, dec, specs, fspecs, {});
2060 template <
typename Char,
typename OutputIt,
typename T,
2061 FMT_ENABLE_IF(std::is_floating_point<T>::value &&
2062 !is_fast_float<T>::value)>
2063 inline auto write(OutputIt out, T value) -> OutputIt {
2067 template <
typename Char,
typename OutputIt>
2070 FMT_ASSERT(
false,
"");
2074 template <
typename Char,
typename OutputIt>
2077 auto it = reserve(out, value.
size());
2078 it = copy_str_noinline<Char>(value.begin(), value.end(), it);
2079 return base_iterator(out, it);
2082 template <
typename Char,
typename OutputIt,
typename T,
2084 constexpr
auto write(OutputIt out,
const T& value) -> OutputIt {
2085 return write<Char>(out, to_string_view(value));
2088 template <
typename Char,
typename OutputIt,
typename T,
2090 !std::is_same<T, bool>::value &&
2091 !std::is_same<T, Char>::value)>
2092 FMT_CONSTEXPR
auto write(OutputIt out, T value) -> OutputIt {
2093 auto abs_value =
static_cast<uint32_or_64_or_128_t<T>
>(value);
2094 bool negative = is_negative(value);
2096 if (negative) abs_value = ~abs_value + 1;
2097 int num_digits = count_digits(abs_value);
2098 auto size = (negative ? 1 : 0) + static_cast<size_t>(num_digits);
2099 auto it = reserve(out, size);
2100 if (
auto ptr = to_pointer<Char>(it, size)) {
2101 if (negative) *ptr++ =
static_cast<Char
>(
'-');
2102 format_decimal<Char>(ptr, abs_value, num_digits);
2105 if (negative) *it++ =
static_cast<Char
>(
'-');
2106 it = format_decimal<Char>(it, abs_value, num_digits).end;
2107 return base_iterator(out, it);
2112 typename Char,
typename OutputIt,
typename T,
2114 std::is_enum<T>::value && !std::is_same<T, Char>::value &&
2117 FMT_ENABLE_IF(check)>
2118 FMT_CONSTEXPR
auto write(OutputIt out, T value) -> OutputIt {
2120 out,
static_cast<typename std::underlying_type<T>::type
>(value));
2123 template <
typename Char,
typename OutputIt,
typename T,
2124 FMT_ENABLE_IF(std::is_same<T, bool>::value)>
2125 FMT_CONSTEXPR
auto write(OutputIt out, T value,
2128 return specs.type != presentation_type::none &&
2129 specs.type != presentation_type::string
2130 ? write(out, value ? 1 : 0, specs, {})
2131 : write_bytes(out, value ?
"true" :
"false", specs);
2134 template <
typename Char,
typename OutputIt>
2135 FMT_CONSTEXPR
auto write(OutputIt out, Char value) -> OutputIt {
2136 auto it = reserve(out, 1);
2138 return base_iterator(out, it);
2141 template <
typename Char,
typename OutputIt>
2142 FMT_CONSTEXPR_CHAR_TRAITS
auto write(OutputIt out,
const Char* value)
2145 throw_format_error(
"string pointer is null");
2152 template <
typename Char,
typename OutputIt,
typename T,
2153 FMT_ENABLE_IF(std::is_same<T, void>::value)>
2154 auto write(OutputIt out,
const T* value,
2158 return write_ptr<Char>(out, to_uintptr(value), &specs);
2162 template <
typename Char,
typename OutputIt,
typename T,
2164 FMT_CONSTEXPR
auto write(OutputIt out,
const T& value) -> enable_if_t<
2166 !std::is_same<T, Char>::value &&
2167 !std::is_same<
const T&,
2173 template <
typename Char,
typename OutputIt,
typename T,
2175 FMT_CONSTEXPR
auto write(OutputIt out,
const T& value)
2176 -> enable_if_t<mapped_type_constant<T, Context>::value == type::custom_type,
2178 using formatter_type =
2179 conditional_t<has_formatter<T, Context>::value,
2180 typename Context::template formatter_type<T>,
2182 auto ctx = Context(out, {}, {});
2183 return formatter_type().format(value, ctx);
2189 using iterator = buffer_appender<Char>;
2196 template <
typename T>
auto operator()(T value) -> iterator {
2197 return write<Char>(out, value);
2201 context format_ctx(out, args, loc);
2202 h.format(parse_ctx, format_ctx);
2203 return format_ctx.out();
2208 using iterator = buffer_appender<Char>;
2215 template <
typename T>
2216 FMT_CONSTEXPR FMT_INLINE
auto operator()(T value) -> iterator {
2217 return detail::write(out, value, specs, locale);
2232 h.format(parse_ctx, ctx);
2234 template <
typename T>
void operator()(T)
const {}
2237 template <
typename T>
2239 bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value &&
2240 !std::is_same<T, char>::value &&
2241 !std::is_same<T, wchar_t>::value>;
2245 explicit FMT_CONSTEXPR
width_checker(ErrorHandler& eh) : handler_(eh) {}
2247 template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
2248 FMT_CONSTEXPR
auto operator()(T value) ->
unsigned long long {
2249 if (is_negative(value)) handler_.on_error(
"negative width");
2250 return static_cast<unsigned long long>(value);
2253 template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
2254 FMT_CONSTEXPR
auto operator()(T) ->
unsigned long long {
2255 handler_.on_error(
"width is not integer");
2260 ErrorHandler& handler_;
2267 template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
2268 FMT_CONSTEXPR
auto operator()(T value) ->
unsigned long long {
2269 if (is_negative(value)) handler_.on_error(
"negative precision");
2270 return static_cast<unsigned long long>(value);
2273 template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
2274 FMT_CONSTEXPR
auto operator()(T) ->
unsigned long long {
2275 handler_.on_error(
"precision is not integer");
2280 ErrorHandler& handler_;
2283 template <
template <
typename>
class Handler,
typename FormatArg,
2284 typename ErrorHandler>
2285 FMT_CONSTEXPR
auto get_dynamic_spec(FormatArg arg, ErrorHandler eh) ->
int {
2286 unsigned long long value = visit_format_arg(Handler<ErrorHandler>(eh), arg);
2287 if (value > to_unsigned(max_value<int>())) eh.on_error(
"number is too big");
2288 return static_cast<int>(value);
2291 template <
typename Context,
typename ID>
2292 FMT_CONSTEXPR
auto get_arg(Context& ctx, ID
id) ->
2293 typename Context::format_arg {
2294 auto arg = ctx.arg(
id);
2295 if (!arg) ctx.on_error(
"argument not found");
2309 return detail::get_arg(context_, parse_context_.
next_arg_id());
2312 FMT_CONSTEXPR
auto get_arg(
int arg_id) ->
format_arg {
2314 return detail::get_arg(context_, arg_id);
2319 return detail::get_arg(context_, arg_id);
2328 template <
typename Id> FMT_CONSTEXPR
void on_dynamic_width(Id arg_id) {
2329 this->specs_.width = get_dynamic_spec<width_checker>(
2330 get_arg(arg_id), context_.error_handler());
2333 template <
typename Id> FMT_CONSTEXPR
void on_dynamic_precision(Id arg_id) {
2334 this->specs_.precision = get_dynamic_spec<precision_checker>(
2335 get_arg(arg_id), context_.error_handler());
2338 void on_error(
const char* message) { context_.on_error(message); }
2341 template <
template <
typename>
class Handler,
typename Context>
2342 FMT_CONSTEXPR
void handle_dynamic_spec(
int& value,
2346 case arg_id_kind::none:
2348 case arg_id_kind::index:
2349 value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.index),
2350 ctx.error_handler());
2352 case arg_id_kind::name:
2353 value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.name),
2354 ctx.error_handler());
2359 #define FMT_STRING_IMPL(s, base, explicit) \ 2363 struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \ 2364 using char_type = fmt::remove_cvref_t<decltype(s[0])>; \ 2365 FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \ 2366 operator fmt::basic_string_view<char_type>() const { \ 2367 return fmt::detail_exported::compile_string_to_view<char_type>(s); \ 2370 return FMT_COMPILE_STRING(); \ 2383 #define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string, ) 2385 #if FMT_USE_USER_DEFINED_LITERALS 2386 template <
typename Char>
struct udl_formatter {
2389 template <
typename... T>
2390 auto operator()(T&&... args)
const -> std::basic_string<Char> {
2391 return vformat(str, fmt::make_args_checked<T...>(str, args...));
2395 # if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 2396 template <
typename T,
typename Char,
size_t N,
2397 fmt::detail_exported::fixed_string<Char, N> Str>
2398 struct statically_named_arg :
view {
2399 static constexpr
auto name = Str.data;
2402 statically_named_arg(
const T& v) : value(v) {}
2405 template <
typename T,
typename Char,
size_t N,
2406 fmt::detail_exported::fixed_string<Char, N> Str>
2407 struct is_named_arg<statically_named_arg<T, Char, N, Str>> : std::true_type {};
2409 template <
typename T,
typename Char,
size_t N,
2410 fmt::detail_exported::fixed_string<Char, N> Str>
2412 : std::true_type {};
2414 template <
typename Char,
size_t N,
2415 fmt::detail_exported::fixed_string<Char, N> Str>
2417 template <
typename T>
auto operator=(T&& value)
const {
2418 return statically_named_arg<T, Char, N, Str>(std::forward<T>(value));
2422 template <
typename Char>
struct udl_arg {
2426 return {str, std::forward<T>(value)};
2430 #endif // FMT_USE_USER_DEFINED_LITERALS 2432 template <
typename Locale,
typename Char>
2435 -> std::basic_string<Char> {
2437 detail::vformat_to(buffer, format_str, args, detail::locale_ref(loc));
2438 return {buffer.data(), buffer.size()};
2441 using format_func = void (*)(detail::buffer<char>&, int,
const char*);
2443 FMT_API
void format_error_code(
buffer<char>& out,
int error_code,
2446 FMT_API
void report_error(format_func func,
int error_code,
2447 const char* message) FMT_NOEXCEPT;
2448 FMT_END_DETAIL_NAMESPACE
2450 FMT_API
auto vsystem_error(
int error_code,
string_view format_str,
2470 template <
typename... T>
2472 -> std::system_error {
2473 return vsystem_error(error_code, fmt, fmt::make_format_args(args...));
2492 FMT_API
void format_system_error(detail::buffer<char>& out,
int error_code,
2493 const char* message) FMT_NOEXCEPT;
2497 FMT_API
void report_system_error(
int error_code,
2498 const char* message) FMT_NOEXCEPT;
2505 enum { buffer_size = std::numeric_limits<unsigned long long>::digits10 + 3 };
2506 mutable char buffer_[buffer_size];
2509 template <
typename UInt>
auto format_unsigned(UInt value) ->
char* {
2510 auto n =
static_cast<detail::uint32_or_64_or_128_t<UInt>
>(value);
2511 return detail::format_decimal(buffer_, n, buffer_size - 1).begin;
2514 template <
typename Int>
auto format_signed(Int value) ->
char* {
2515 auto abs_value =
static_cast<detail::uint32_or_64_or_128_t<Int>
>(value);
2516 bool negative = value < 0;
2517 if (negative) abs_value = 0 - abs_value;
2518 auto begin = format_unsigned(abs_value);
2519 if (negative) *--begin =
'-';
2524 explicit format_int(
int value) : str_(format_signed(value)) {}
2525 explicit format_int(
long value) : str_(format_signed(value)) {}
2526 explicit format_int(
long long value) : str_(format_signed(value)) {}
2527 explicit format_int(
unsigned value) : str_(format_unsigned(value)) {}
2528 explicit format_int(
unsigned long value) : str_(format_unsigned(value)) {}
2529 explicit format_int(
unsigned long long value)
2530 : str_(format_unsigned(value)) {}
2534 return detail::to_unsigned(buffer_ - str_ + buffer_size - 1);
2541 auto data() const -> const
char* {
return str_; }
2548 buffer_[buffer_size - 1] =
'\0';
2557 auto str() const ->
std::
string {
return std::string(str_, size()); }
2560 template <
typename T,
typename Char>
2561 template <
typename FormatContext>
2562 FMT_CONSTEXPR FMT_INLINE
auto 2564 enable_if_t<detail::type_constant<T, Char>::value !=
2565 detail::type::custom_type>>::format(
const T& val,
2567 const -> decltype(ctx.out()) {
2568 if (specs_.width_ref.kind != detail::arg_id_kind::none ||
2569 specs_.precision_ref.kind != detail::arg_id_kind::none) {
2570 auto specs = specs_;
2571 detail::handle_dynamic_spec<detail::width_checker>(specs.width,
2572 specs.width_ref, ctx);
2573 detail::handle_dynamic_spec<detail::precision_checker>(
2574 specs.precision, specs.precision_ref, ctx);
2575 return detail::write<Char>(ctx.out(), val, specs, ctx.locale());
2577 return detail::write<Char>(ctx.out(), val, specs_, ctx.locale());
2580 #define FMT_FORMAT_AS(Type, Base) \ 2581 template <typename Char> \ 2582 struct formatter<Type, Char> : formatter<Base, Char> { \ 2583 template <typename FormatContext> \ 2584 auto format(Type const& val, FormatContext& ctx) const \ 2585 -> decltype(ctx.out()) { \ 2586 return formatter<Base, Char>::format(static_cast<Base>(val), ctx); \ 2590 FMT_FORMAT_AS(
signed char,
int);
2591 FMT_FORMAT_AS(
unsigned char,
unsigned);
2592 FMT_FORMAT_AS(
short,
int);
2593 FMT_FORMAT_AS(
unsigned short,
unsigned);
2594 FMT_FORMAT_AS(
long,
long long);
2595 FMT_FORMAT_AS(
unsigned long,
unsigned long long);
2596 FMT_FORMAT_AS(Char*,
const Char*);
2598 FMT_FORMAT_AS(std::nullptr_t,
const void*);
2599 FMT_FORMAT_AS(detail::byte,
unsigned char);
2602 template <
typename Char>
2604 template <
typename FormatContext>
2605 auto format(
void* val, FormatContext& ctx)
const -> decltype(ctx.out()) {
2610 template <
typename Char,
size_t N>
2612 template <
typename FormatContext>
2613 FMT_CONSTEXPR
auto format(
const Char* val, FormatContext& ctx)
const 2614 -> decltype(ctx.out()) {
2633 detail::dynamic_format_specs<Char> specs_;
2634 const Char* format_str_;
2636 struct null_handler : detail::error_handler {
2637 void on_align(align_t) {}
2638 void on_sign(sign_t) {}
2642 template <
typename Context>
void handle_specs(Context& ctx) {
2643 detail::handle_dynamic_spec<detail::width_checker>(specs_.width,
2644 specs_.width_ref, ctx);
2645 detail::handle_dynamic_spec<detail::precision_checker>(
2646 specs_.precision, specs_.precision_ref, ctx);
2650 template <
typename ParseContext>
2651 FMT_CONSTEXPR
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
2652 format_str_ = ctx.begin();
2654 detail::dynamic_specs_handler<ParseContext> handler(specs_, ctx);
2655 return detail::parse_format_specs(ctx.begin(), ctx.end(), handler);
2658 template <
typename T,
typename FormatContext>
2659 auto format(
const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
2661 detail::specs_checker<null_handler> checker(
2662 null_handler(), detail::mapped_type_constant<T, FormatContext>::value);
2663 checker.on_align(specs_.align);
2664 if (specs_.sign != sign::none) checker.on_sign(specs_.sign);
2665 if (specs_.alt) checker.on_hash();
2666 if (specs_.precision >= 0) checker.end_precision();
2667 return detail::write<Char>(ctx.out(), val, specs_, ctx.locale());
2680 template <
typename T>
auto ptr(T p) ->
const void* {
2681 static_assert(std::is_pointer<T>::value,
"");
2682 return detail::bit_cast<
const void*>(p);
2684 template <
typename T>
auto ptr(
const std::unique_ptr<T>& p) ->
const void* {
2687 template <
typename T>
auto ptr(
const std::shared_ptr<T>& p) ->
const void* {
2702 detail::dynamic_format_specs<char> specs_;
2705 template <
typename ParseContext>
2706 FMT_CONSTEXPR
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
2707 using handler_type = detail::dynamic_specs_handler<ParseContext>;
2708 detail::specs_checker<handler_type> handler(handler_type(specs_, ctx),
2709 detail::type::string_type);
2710 auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
2711 detail::check_string_type_spec(specs_.type, ctx.error_handler());
2715 template <
typename FormatContext>
2716 auto format(bytes b, FormatContext& ctx) -> decltype(ctx.out()) {
2717 detail::handle_dynamic_spec<detail::width_checker>(specs_.width,
2718 specs_.width_ref, ctx);
2719 detail::handle_dynamic_spec<detail::precision_checker>(
2720 specs_.precision, specs_.precision_ref, ctx);
2721 return detail::write_bytes(ctx.out(), b.data_, specs_);
2745 detail::dynamic_format_specs<char> specs_;
2748 template <
typename ParseContext>
2749 FMT_CONSTEXPR
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
2750 using handler_type = detail::dynamic_specs_handler<ParseContext>;
2751 detail::specs_checker<handler_type> handler(handler_type(specs_, ctx),
2752 detail::type::int_type);
2753 auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
2754 detail::check_string_type_spec(specs_.type, ctx.error_handler());
2758 template <
typename FormatContext>
2760 -> decltype(ctx.out()) {
2761 detail::handle_dynamic_spec<detail::width_checker>(specs_.width,
2762 specs_.width_ref, ctx);
2763 detail::handle_dynamic_spec<detail::precision_checker>(
2764 specs_.precision, specs_.precision_ref, ctx);
2765 return detail::write_int_localized(
2766 ctx.out(),
static_cast<detail::uint64_or_128_t<T>
>(t.value), 0, specs_,
2767 detail::digit_grouping<char>({
"\3",
','}));
2771 template <
typename It,
typename Sentinel,
typename Char =
char>
2778 : begin(b), end(e), sep(s) {}
2781 template <
typename It,
typename Sentinel,
typename Char>
2784 template <
typename It,
typename Sentinel,
typename Char>
2788 #ifdef __cpp_lib_ranges 2789 std::iter_value_t<It>;
2791 typename std::iterator_traits<It>::value_type;
2794 using mapper = detail::arg_mapper<context>;
2796 template <typename T, FMT_ENABLE_IF(has_formatter<T, context>::value)>
2797 static auto map(
const T& value) ->
const T& {
2800 template <typename T, FMT_ENABLE_IF(!has_formatter<T, context>::value)>
2801 static auto map(
const T& value) -> decltype(mapper().map(value)) {
2802 return mapper().map(value);
2805 using formatter_type =
2806 conditional_t<is_formattable<value_type, Char>::value,
2808 std::declval<const value_type&>()))>,
2810 detail::fallback_formatter<value_type, Char>>;
2812 formatter_type value_formatter_;
2815 template <
typename ParseContext>
2816 FMT_CONSTEXPR
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
2817 return value_formatter_.parse(ctx);
2820 template <
typename FormatContext>
2822 -> decltype(ctx.out()) {
2823 auto it = value.begin;
2824 auto out = ctx.out();
2825 if (it != value.end) {
2826 out = value_formatter_.format(map(*it), ctx);
2828 while (it != value.end) {
2829 out = detail::copy_str<Char>(value.sep.begin(), value.sep.end(), out);
2830 ctx.advance_to(out);
2831 out = value_formatter_.format(map(*it), ctx);
2843 template <
typename It,
typename Sentinel>
2845 return {begin, end, sep};
2864 template <
typename Range>
2867 return join(std::begin(
range), std::end(
range), sep);
2881 template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
2882 inline auto to_string(
const T& value) -> std::string {
2883 auto result = std::string();
2884 detail::write<char>(std::back_inserter(result), value);
2888 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
2889 FMT_NODISCARD
inline auto to_string(T value) -> std::string {
2892 constexpr
int max_size = detail::digits10<T>() + 2;
2893 char buffer[max_size > 5 ?
static_cast<unsigned>(max_size) : 5];
2894 char* begin = buffer;
2895 return std::string(begin, detail::write<char>(begin, value));
2898 template <
typename Char,
size_t SIZE>
2900 -> std::basic_string<Char> {
2901 auto size = buf.size();
2902 detail::assume(size < std::basic_string<Char>().max_size());
2903 return std::basic_string<Char>(buf.data(), size);
2906 FMT_BEGIN_DETAIL_NAMESPACE
2908 template <
typename Char>
2915 using detail::arg_formatter;
2916 using detail::buffer_appender;
2917 using detail::custom_formatter;
2918 using detail::default_arg_formatter;
2919 using detail::get_arg;
2920 using detail::locale_ref;
2921 using detail::parse_format_specs;
2922 using detail::specs_checker;
2923 using detail::specs_handler;
2924 using detail::to_unsigned;
2926 using detail::write;
2927 auto out = buffer_appender<Char>(buf);
2928 if (fmt.
size() == 2 && equal2(fmt.
data(),
"{}")) {
2929 auto arg = args.
get(0);
2941 : parse_context(str), context(out, args, loc) {}
2943 void on_text(
const Char* begin,
const Char* end) {
2945 context.advance_to(write<Char>(context.out(), text));
2948 FMT_CONSTEXPR
auto on_arg_id() ->
int {
2951 FMT_CONSTEXPR
auto on_arg_id(
int id) ->
int {
2955 int arg_id = context.arg_id(
id);
2956 if (arg_id < 0) on_error(
"argument not found");
2960 FMT_INLINE
void on_replacement_field(
int id,
const Char*) {
2961 auto arg = get_arg(context,
id);
2962 context.advance_to(visit_format_arg(
2968 auto on_format_specs(
int id,
const Char* begin,
const Char* end)
2970 auto arg = get_arg(context,
id);
2971 if (arg.type() == type::custom_type) {
2973 (begin - &*parse_context.
begin()));
2975 return parse_context.
begin();
2980 begin = parse_format_specs(begin, end, handler);
2981 if (begin == end || *begin !=
'}')
2982 on_error(
"missing '}' in format string");
2984 context.advance_to(visit_format_arg(f, arg));
2988 detail::parse_format_string<false>(fmt, format_handler(out, fmt, args, loc));
2991 #ifndef FMT_HEADER_ONLY 2992 extern template FMT_API
auto thousands_sep_impl<char>(
locale_ref)
2994 extern template FMT_API
auto thousands_sep_impl<wchar_t>(
locale_ref)
2996 extern template FMT_API
auto decimal_point_impl(
locale_ref) -> char;
2997 extern template FMT_API
auto decimal_point_impl(
locale_ref) -> wchar_t;
2998 extern template auto format_float<double>(
double value,
int precision,
3001 extern template auto format_float<long double>(
long double value,
int precision,
3005 extern template auto snprintf_float<double>(
double value,
int precision,
3008 extern template auto snprintf_float<long double>(
long double value,
3012 #endif // FMT_HEADER_ONLY 3014 FMT_END_DETAIL_NAMESPACE
3016 #if FMT_USE_USER_DEFINED_LITERALS 3028 # if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 3029 template <detail_exported::fixed_
string Str>
3030 constexpr
auto operator""_a()
3031 -> detail::udl_arg<remove_cvref_t<decltype(Str.data[0])>,
3032 sizeof(Str.data) /
sizeof(decltype(Str.data[0])), Str> {
3036 constexpr
auto operator"" _a(
const char* s,
size_t) -> detail::udl_arg<char> {
3043 FMT_DEPRECATED constexpr
auto operator"" _format(
const char* s,
size_t n)
3044 -> detail::udl_formatter<char> {
3048 #endif // FMT_USE_USER_DEFINED_LITERALS 3050 template <typename Locale, FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
3053 return detail::vformat(loc, fmt, args);
3056 template <
typename Locale,
typename... T,
3057 FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
3060 return vformat(loc,
string_view(fmt), fmt::make_format_args(args...));
3063 template <
typename... T,
size_t SIZE,
typename Allocator>
3067 detail::vformat_to(buf,
string_view(fmt), fmt::make_format_args(args...));
3071 template <
typename OutputIt,
typename Locale,
3072 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value&&
3073 detail::is_locale<Locale>::value)>
3074 auto vformat_to(OutputIt out,
const Locale& loc,
string_view fmt,
3076 using detail::get_buffer;
3077 auto&& buf = get_buffer<char>(out);
3078 detail::vformat_to(buf, fmt, args, detail::locale_ref(loc));
3079 return detail::get_iterator(buf);
3082 template <
typename OutputIt,
typename Locale,
typename... T,
3083 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value&&
3084 detail::is_locale<Locale>::value)>
3085 FMT_INLINE
auto format_to(OutputIt out,
const Locale& loc,
3087 return vformat_to(out, loc, fmt, fmt::make_format_args(args...));
3090 FMT_MODULE_EXPORT_END
3093 #ifdef FMT_DEPRECATED_INCLUDE_XCHAR 3097 #ifdef FMT_HEADER_ONLY 3098 # define FMT_FUNC inline 3099 # include "format-inl.h" 3104 #endif // FMT_FORMAT_H_ Definition: format.h:2726
A dynamically growing memory buffer for trivially copyable/constructible types with the first SIZE el...
Definition: format.h:677
Definition: format.h:1257
constexpr auto size() const FMT_NOEXCEPT -> size_t
Returns the size of this buffer.
Definition: core.h:820
void reserve(size_t new_capacity)
Increases the buffer capacity to new_capacity.
Definition: format.h:766
FMT_CONSTEXPR void advance_to(iterator it)
Advances the begin iterator to it.
Definition: core.h:663
constexpr auto begin() const FMT_NOEXCEPT -> iterator
Returns an iterator to the beginning of the format string range being parsed.
Definition: core.h:651
Definition: format.h:1052
FMT_CONSTEXPR20 void resize(size_t count)
Resizes the buffer to contain count elements.
Definition: format.h:763
Definition: generic.hpp:135
Definition: format.h:1448
constexpr auto capacity() const FMT_NOEXCEPT -> size_t
Returns the capacity of this buffer.
Definition: core.h:823
Definition: format.h:2243
Definition: format.h:1200
constexpr auto data() const FMT_NOEXCEPT -> const Char *
Returns a pointer to the string data.
Definition: core.h:492
void append(const U *begin, const U *end)
Appends data to the end of the buffer.
FMT_CONSTEXPR auto next_arg_id() -> int
Reports an error if using the manual argument indexing; otherwise returns the next argument index and...
Definition: core.h:671
Definition: format.h:1541
constexpr auto size() const FMT_NOEXCEPT -> size_t
Returns the string size.
Definition: core.h:495
Definition: format.h:2772
Definition: sc_data.cpp:17
Definition: format.h:1188
FMT_CONSTEXPR auto data() FMT_NOEXCEPT -> T *
Returns a pointer to the buffer data.
Definition: core.h:826
FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer &&other) FMT_NOEXCEPT
Constructs a :class:fmt::basic_memory_buffer object moving the content of the other object to it...
Definition: format.h:738
Definition: format.h:2300
Definition: format.h:1701
auto operator=(basic_memory_buffer &&other) FMT_NOEXCEPT -> basic_memory_buffer &
Moves the content of the other basic_memory_buffer object to this one.
Definition: format.h:748
Definition: format.h:1400
Definition: format.h:1203
Definition: color.hpp:198
FMT_CONSTEXPR void check_arg_id(int)
Reports an error if using the automatic argument indexing; otherwise switches to the manual indexing...
Definition: core.h:683
Definition: format.h:2691
Definition: format.h:1912
Definition: format.h:2263