46 #ifdef __INTEL_COMPILER 47 # define FMT_ICC_VERSION __INTEL_COMPILER 49 # define FMT_ICC_VERSION __ICL 51 # define FMT_ICC_VERSION 0 55 # define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__) 57 # define FMT_CUDA_VERSION 0 61 # define FMT_HAS_BUILTIN(x) __has_builtin(x) 63 # define FMT_HAS_BUILTIN(x) 0 66 #if FMT_GCC_VERSION || FMT_CLANG_VERSION 67 # define FMT_NOINLINE __attribute__((noinline)) 72 #if __cplusplus == 201103L || __cplusplus == 201402L 73 # if defined(__INTEL_COMPILER) || defined(__PGI) 74 # define FMT_FALLTHROUGH 75 # elif defined(__clang__) 76 # define FMT_FALLTHROUGH [[clang::fallthrough]] 77 # elif FMT_GCC_VERSION >= 700 && \ 78 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) 79 # define FMT_FALLTHROUGH [[gnu::fallthrough]] 81 # define FMT_FALLTHROUGH 83 #elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) || \ 84 (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) 85 # define FMT_FALLTHROUGH [[fallthrough]] 87 # define FMT_FALLTHROUGH 90 #ifndef FMT_MAYBE_UNUSED 91 # if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) 92 # define FMT_MAYBE_UNUSED [[maybe_unused]] 94 # define FMT_MAYBE_UNUSED 100 # if FMT_MSC_VER || FMT_NVCC 103 template <
typename Exception>
inline void do_throw(
const Exception& x) {
106 volatile bool b =
true;
111 # define FMT_THROW(x) detail::do_throw(x) 113 # define FMT_THROW(x) throw x 116 # define FMT_THROW(x) \ 118 static_cast<void>(sizeof(x)); \ 119 FMT_ASSERT(false, ""); \ 126 # define FMT_CATCH(x) catch (x) 128 # define FMT_TRY if (true) 129 # define FMT_CATCH(x) if (false) 132 #ifndef FMT_USE_USER_DEFINED_LITERALS 134 # if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \ 135 FMT_MSC_VER >= 1900) && \ 136 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 480) 137 # define FMT_USE_USER_DEFINED_LITERALS 1 139 # define FMT_USE_USER_DEFINED_LITERALS 0 143 #ifndef FMT_USE_UDL_TEMPLATE 146 # if FMT_USE_USER_DEFINED_LITERALS && \ 147 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 501) && \ 148 ((FMT_GCC_VERSION >= 604 && __cplusplus >= 201402L) || \ 149 FMT_CLANG_VERSION >= 304) && \ 150 !defined(__PGI) && !defined(__NVCC__) 151 # define FMT_USE_UDL_TEMPLATE 1 153 # define FMT_USE_UDL_TEMPLATE 0 157 #ifndef FMT_USE_FLOAT 158 # define FMT_USE_FLOAT 1 161 #ifndef FMT_USE_DOUBLE 162 # define FMT_USE_DOUBLE 1 165 #ifndef FMT_USE_LONG_DOUBLE 166 # define FMT_USE_LONG_DOUBLE 1 173 #if !defined(FMT_REDUCE_INT_INSTANTIATIONS) 174 # define FMT_REDUCE_INT_INSTANTIATIONS 0 179 #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)) && !FMT_MSC_VER 180 # define FMT_BUILTIN_CLZ(n) __builtin_clz(n) 182 #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clzll)) && !FMT_MSC_VER 183 # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) 185 #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_ctz)) 186 # define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) 188 #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_ctzll)) 189 # define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) 199 #if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && \ 200 !defined(FMT_BUILTIN_CTZLL) && !defined(_MANAGED) 205 # pragma intrinsic(_BitScanForward) 206 # pragma intrinsic(_BitScanReverse) 208 # if defined(_WIN64) && !defined(__clang__) 209 # pragma intrinsic(_BitScanForward64) 210 # pragma intrinsic(_BitScanReverse64) 213 inline int clz(uint32_t x) {
215 _BitScanReverse(&r, x);
216 FMT_ASSERT(x != 0,
"");
220 FMT_SUPPRESS_MSC_WARNING(6102)
221 return 31 ^ static_cast<
int>(r);
223 # define FMT_BUILTIN_CLZ(n) detail::clz(n) 225 inline int clzll(uint64_t x) {
228 _BitScanReverse64(&r, x);
231 if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
return 63 ^ (r + 32);
233 _BitScanReverse(&r, static_cast<uint32_t>(x));
235 FMT_ASSERT(x != 0,
"");
236 FMT_SUPPRESS_MSC_WARNING(6102)
237 return 63 ^ static_cast<
int>(r);
239 # define FMT_BUILTIN_CLZLL(n) detail::clzll(n) 241 inline int ctz(uint32_t x) {
243 _BitScanForward(&r, x);
244 FMT_ASSERT(x != 0,
"");
245 FMT_SUPPRESS_MSC_WARNING(6102)
246 return static_cast<
int>(r);
248 # define FMT_BUILTIN_CTZ(n) detail::ctz(n) 250 inline int ctzll(uint64_t x) {
252 FMT_ASSERT(x != 0,
"");
253 FMT_SUPPRESS_MSC_WARNING(6102)
255 _BitScanForward64(&r, x);
258 if (_BitScanForward(&r, static_cast<uint32_t>(x)))
return static_cast<int>(r);
260 _BitScanForward(&r, static_cast<uint32_t>(x >> 32));
263 return static_cast<int>(r);
265 # define FMT_BUILTIN_CTZLL(n) detail::ctzll(n) 271 #ifndef FMT_DEPRECATED_NUMERIC_ALIGN 272 # define FMT_DEPRECATED_NUMERIC_ALIGN 0 281 template <
typename Dest,
typename Source>
282 inline Dest bit_cast(
const Source& source) {
283 static_assert(
sizeof(Dest) ==
sizeof(Source),
"size mismatch");
285 std::memcpy(&dest, &source,
sizeof(dest));
289 inline bool is_big_endian() {
292 char data[
sizeof(u)];
294 return bit_cast<
bytes>(u).data[0] == 0;
299 unsigned char value[
sizeof(
void*)];
304 if (is_big_endian()) {
305 for (
size_t i = 0, j =
sizeof(
void*) - 1; i < j; ++i, --j)
322 template <
typename T> constexpr T max_value() {
323 return (std::numeric_limits<T>::max)();
325 template <
typename T> constexpr
int num_bits() {
326 return std::numeric_limits<T>::digits;
329 template <> constexpr
int num_bits<int128_t>() {
return 128; }
330 template <> constexpr
int num_bits<uint128_t>() {
return 128; }
331 template <> constexpr
int num_bits<fallback_uintptr>() {
332 return static_cast<int>(
sizeof(
void*) *
333 std::numeric_limits<unsigned char>::digits);
336 FMT_INLINE
void assume(
bool condition) {
338 #if FMT_HAS_BUILTIN(__builtin_assume) 339 __builtin_assume(condition);
344 template <
typename T>
345 using iterator_t = decltype(std::begin(std::declval<T&>()));
346 template <
typename T>
using sentinel_t = decltype(std::end(std::declval<T&>()));
349 template <
typename Char>
inline Char* get_data(std::basic_string<Char>&
s) {
352 template <
typename Container>
353 inline typename Container::value_type* get_data(Container& c) {
357 #if defined(_SECURE_SCL) && _SECURE_SCL 359 template <
typename T>
using checked_ptr = stdext::checked_array_iterator<T*>;
360 template <
typename T> checked_ptr<T> make_checked(T* p,
size_t size) {
364 template <
typename T>
using checked_ptr = T*;
365 template <
typename T>
inline T* make_checked(T* p,
size_t) {
return p; }
368 template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
369 #
if FMT_CLANG_VERSION
370 __attribute__((no_sanitize(
"undefined")))
372 inline checked_ptr<typename Container::value_type>
373 reserve(std::back_insert_iterator<Container> it,
size_t n) {
374 Container& c = get_container(it);
375 size_t size = c.size();
377 return make_checked(get_data(c) + size, n);
380 template <
typename T>
383 buf.try_reserve(buf.
size() + n);
387 template <
typename Iterator>
inline Iterator& reserve(Iterator& it,
size_t) {
391 template <
typename T,
typename OutputIt>
392 constexpr T* to_pointer(OutputIt,
size_t) {
397 auto size = buf.
size();
398 if (buf.
capacity() < size + n)
return nullptr;
399 buf.try_resize(size + n);
400 return buf.
data() + size;
403 template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
404 inline std::back_insert_iterator<Container> base_iterator(
405 std::back_insert_iterator<Container>& it,
406 checked_ptr<typename Container::value_type>) {
410 template <
typename Iterator>
411 inline Iterator base_iterator(Iterator, Iterator it) {
422 using iterator_category = std::output_iterator_tag;
423 using difference_type = std::ptrdiff_t;
424 using pointer = void;
425 using reference = void;
429 template <
typename T>
void operator=(
const T&) {}
434 size_t count()
const {
return count_; }
447 it.count_ +=
static_cast<size_t>(n);
461 : out_(out), limit_(limit), count_(0) {}
464 using iterator_category = std::output_iterator_tag;
465 using value_type =
typename std::iterator_traits<OutputIt>::value_type;
466 using difference_type = void;
467 using pointer = void;
468 using reference = void;
472 OutputIt base()
const {
return out_; }
473 size_t count()
const {
return count_; }
478 template <
typename OutputIt,
479 typename Enable =
typename std::is_void<
480 typename std::iterator_traits<OutputIt>::value_type>::type>
483 template <
typename OutputIt>
486 mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
489 using value_type =
typename truncating_iterator_base<OutputIt>::value_type;
495 if (this->count_++ < this->limit_) ++this->out_;
505 value_type& operator*()
const {
506 return this->count_ < this->limit_ ? *this->out_ : blackhole_;
510 template <
typename OutputIt>
518 if (this->count_++ < this->limit_) *this->out_++ = val;
527 template <
typename Char>
535 size_t num_code_points = 0;
536 for (
size_t i = 0, size = s.
size(); i != size; ++i) {
537 if ((data[i] & 0xc0) != 0x80) ++num_code_points;
539 return num_code_points;
544 reinterpret_cast<const char*>(s.
data()), s.
size()));
547 template <
typename Char>
549 size_t size = s.
size();
550 return n < size ? n : size;
556 size_t num_code_points = 0;
557 for (
size_t i = 0, size = s.
size(); i != size; ++i) {
558 if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) {
565 template <
typename InputIt,
typename OutChar>
566 using needs_conversion = bool_constant<
567 std::is_same<typename std::iterator_traits<InputIt>::value_type,
569 std::is_same<OutChar, char8_type>::value>;
571 template <
typename OutChar,
typename InputIt,
typename OutputIt,
572 FMT_ENABLE_IF(!needs_conversion<InputIt, OutChar>::value)>
573 OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) {
574 return std::copy(begin, end, it);
577 template <
typename OutChar,
typename InputIt,
typename OutputIt,
578 FMT_ENABLE_IF(needs_conversion<InputIt, OutChar>::value)>
579 OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) {
580 return std::transform(begin, end, it,
581 [](
char c) {
return static_cast<char8_type
>(c); });
584 template <
typename Char,
typename InputIt>
587 return it + (end - begin);
590 template <
typename T>
591 using is_fast_float = bool_constant<std::numeric_limits<T>::is_iec559 &&
592 sizeof(T) <=
sizeof(
double)>;
594 #ifndef FMT_USE_FULL_CACHE_DRAGONBOX 595 # define FMT_USE_FULL_CACHE_DRAGONBOX 0 598 template <
typename T>
599 template <
typename U>
602 auto count = to_unsigned(end - begin);
603 try_reserve(size_ + count);
604 auto free_cap = capacity_ - size_;
605 if (free_cap < count) count = free_cap;
606 std::uninitialized_copy_n(begin, count, make_checked(ptr_ + size_, count));
609 }
while (begin != end);
612 template <
typename OutputIt,
typename T,
typename Traits>
614 out_ = std::copy_n(data_, this->limit(this->size()), out_);
621 enum { inline_buffer_size = 500 };
652 template <
typename T,
size_t SIZE = inline_buffer_size,
653 typename Allocator = std::allocator<T>>
663 T* data = this->data();
664 if (data != store_) alloc_.deallocate(data, this->capacity());
668 void grow(
size_t size)
final FMT_OVERRIDE;
671 using value_type = T;
672 using const_reference =
const T&;
676 this->
set(store_, SIZE);
683 alloc_ = std::move(other.alloc_);
684 T* data = other.
data();
685 size_t size = other.
size(), capacity = other.
capacity();
686 if (data == other.store_) {
687 this->
set(store_, capacity);
688 std::uninitialized_copy(other.store_, other.store_ + size,
689 detail::make_checked(store_, capacity));
691 this->
set(data, capacity);
694 other.
set(other.store_, 0);
714 FMT_ASSERT(
this != &other,
"");
721 Allocator get_allocator()
const {
return alloc_; }
727 void resize(
size_t count) { this->try_resize(count); }
730 void reserve(
size_t new_capacity) { this->try_reserve(new_capacity); }
734 template <
typename ContiguousRange>
735 void append(
const ContiguousRange& range) {
736 append(range.data(), range.data() + range.size());
740 template <
typename T,
size_t SIZE,
typename Allocator>
743 if (size > 5000)
throw std::runtime_error(
"fuzz mode - won't grow that much");
745 size_t old_capacity = this->capacity();
746 size_t new_capacity = old_capacity + old_capacity / 2;
747 if (size > new_capacity) new_capacity = size;
748 T* old_data = this->data();
750 std::allocator_traits<Allocator>::allocate(alloc_, new_capacity);
752 std::uninitialized_copy(old_data, old_data + this->size(),
753 detail::make_checked(new_data, new_capacity));
754 this->
set(new_data, new_capacity);
758 if (old_data != store_) alloc_.deallocate(old_data, old_capacity);
764 template <
typename T,
size_t SIZE,
typename Allocator>
772 explicit format_error(
const char* message) : std::runtime_error(message) {}
774 : std::runtime_error(message) {}
784 template <
typename T>
786 std::integral_constant<bool, std::numeric_limits<T>::is_signed ||
787 std::is_same<T, int128_t>::value>;
791 template <typename T, FMT_ENABLE_IF(is_signed<T>::value)>
792 FMT_CONSTEXPR
bool is_negative(T value) {
795 template <typename T, FMT_ENABLE_IF(!is_signed<T>::value)>
796 FMT_CONSTEXPR
bool is_negative(T) {
800 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
801 FMT_CONSTEXPR
bool is_supported_floating_point(T) {
802 return (std::is_same<T, float>::value && FMT_USE_FLOAT) ||
803 (std::is_same<T, double>::value && FMT_USE_DOUBLE) ||
804 (std::is_same<T, long double>::value && FMT_USE_LONG_DOUBLE);
809 template <
typename T>
810 using uint32_or_64_or_128_t =
811 conditional_t<num_bits<T>() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS,
813 conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>;
823 : internal_{
static_cast<uint128_t
>(low) |
824 (static_cast<uint128_t>(high) << 64)} {}
828 uint64_t high()
const FMT_NOEXCEPT {
return uint64_t(internal_ >> 64); }
829 uint64_t low()
const FMT_NOEXCEPT {
return uint64_t(internal_); }
839 uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT : high_{high},
842 uint64_t high()
const FMT_NOEXCEPT {
return high_; }
843 uint64_t low()
const FMT_NOEXCEPT {
return low_; }
846 # if defined(_MSC_VER) && defined(_M_X64) 847 unsigned char carry = _addcarry_u64(0, low_, n, &low_);
848 _addcarry_u64(carry, high_, 0, &high_);
851 uint64_t sum = low_ + n;
852 high_ += (sum < low_ ? 1 : 0);
867 template <
typename T =
void>
struct FMT_EXTERN_TEMPLATE_API
basic_data {
868 static const uint64_t powers_of_10_64[];
869 static const uint32_t zero_or_powers_of_10_32_new[];
870 static const uint64_t zero_or_powers_of_10_64_new[];
871 static const uint64_t grisu_pow10_significands[];
872 static const int16_t grisu_pow10_exponents[];
875 static const uint64_t dragonbox_pow10_significands_64[];
878 static const uint64_t log10_2_significand = 0x4d104d427de7fbcc;
879 #if !FMT_USE_FULL_CACHE_DRAGONBOX 880 static const uint64_t powers_of_5_64[];
881 static const uint32_t dragonbox_pow10_recovery_errors[];
884 using digit_pair =
char[2];
885 static const digit_pair digits[];
886 static const char hex_digits[];
887 static const char foreground_color[];
888 static const char background_color[];
889 static const char reset_color[5];
890 static const wchar_t wreset_color[5];
891 static const char signs[];
892 static const char left_padding_shifts[5];
893 static const char right_padding_shifts[5];
896 static const uint32_t zero_or_powers_of_10_32[];
897 static const uint64_t zero_or_powers_of_10_64[];
902 FMT_INLINE uint16_t bsr2log10(
int bsr) {
903 static constexpr uint16_t
data[] = {
904 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
905 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
906 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
907 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20};
918 #ifdef FMT_BUILTIN_CLZLL 921 inline int count_digits(uint64_t n) {
923 auto t = bsr2log10(FMT_BUILTIN_CLZLL(n | 1) ^ 63);
924 return t - (n < data::zero_or_powers_of_10_64_new[t]);
928 inline int count_digits(uint64_t n) {
934 if (n < 10)
return count;
935 if (n < 100)
return count + 1;
936 if (n < 1000)
return count + 2;
937 if (n < 10000)
return count + 3;
945 inline int count_digits(uint128_t n) {
951 if (n < 10)
return count;
952 if (n < 100)
return count + 1;
953 if (n < 1000)
return count + 2;
954 if (n < 10000)
return count + 3;
962 template <
unsigned BITS,
typename UInt>
inline int count_digits(UInt n) {
966 }
while ((n >>= BITS) != 0);
972 #if FMT_GCC_VERSION || FMT_CLANG_VERSION 973 # define FMT_ALWAYS_INLINE inline __attribute__((always_inline)) 975 # define FMT_ALWAYS_INLINE __forceinline 977 # define FMT_ALWAYS_INLINE inline 981 #if FMT_MSC_VER && !FMT_CLANG_VERSION 982 # define FMT_SAFEBUFFERS __declspec(safebuffers) 984 # define FMT_SAFEBUFFERS 987 #ifdef FMT_BUILTIN_CLZ 989 inline int count_digits(uint32_t n) {
990 auto t = bsr2log10(FMT_BUILTIN_CLZ(n | 1) ^ 31);
991 return t - (n < data::zero_or_powers_of_10_32_new[t]);
995 template <
typename Int> constexpr
int digits10() FMT_NOEXCEPT {
996 return std::numeric_limits<Int>::digits10;
998 template <> constexpr
int digits10<int128_t>() FMT_NOEXCEPT {
return 38; }
999 template <> constexpr
int digits10<uint128_t>() FMT_NOEXCEPT {
return 38; }
1001 template <
typename Char> FMT_API std::string grouping_impl(
locale_ref loc);
1002 template <
typename Char>
inline std::string grouping(
locale_ref loc) {
1003 return grouping_impl<char>(loc);
1005 template <>
inline std::string grouping<wchar_t>(
locale_ref loc) {
1006 return grouping_impl<wchar_t>(loc);
1009 template <
typename Char> FMT_API Char thousands_sep_impl(
locale_ref loc);
1010 template <
typename Char>
inline Char thousands_sep(
locale_ref loc) {
1011 return Char(thousands_sep_impl<char>(loc));
1013 template <>
inline wchar_t thousands_sep(
locale_ref loc) {
1014 return thousands_sep_impl<wchar_t>(loc);
1017 template <
typename Char> FMT_API Char decimal_point_impl(
locale_ref loc);
1018 template <
typename Char>
inline Char decimal_point(
locale_ref loc) {
1019 return Char(decimal_point_impl<char>(loc));
1021 template <>
inline wchar_t decimal_point(
locale_ref loc) {
1022 return decimal_point_impl<wchar_t>(loc);
1026 template <
typename Char>
bool equal2(
const Char* lhs,
const char* rhs) {
1027 return lhs[0] == rhs[0] && lhs[1] == rhs[1];
1029 inline bool equal2(
const char* lhs,
const char* rhs) {
1030 return memcmp(lhs, rhs, 2) == 0;
1034 template <
typename Char>
void copy2(Char* dst,
const char* src) {
1035 *dst++ =
static_cast<Char
>(*src++);
1036 *dst =
static_cast<Char
>(*src);
1038 FMT_INLINE
void copy2(
char* dst,
const char* src) { memcpy(dst, src, 2); }
1048 template <
typename Char,
typename UInt>
1051 FMT_ASSERT(size >= count_digits(value),
"invalid digit count");
1054 while (value >= 100) {
1059 copy2(out, data::digits[value % 100]);
1063 *--out =
static_cast<Char
>(
'0' + value);
1067 copy2(out, data::digits[value]);
1071 template <
typename Char,
typename UInt,
typename Iterator,
1072 FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<Iterator>>::value)>
1076 Char
buffer[digits10<UInt>() + 1];
1077 auto end = format_decimal(
buffer, value, size).end;
1078 return {out, detail::copy_str<Char>(
buffer, end, out)};
1081 template <
unsigned BASE_BITS,
typename Char,
typename UInt>
1082 inline Char* format_uint(Char*
buffer, UInt value,
int num_digits,
1083 bool upper =
false) {
1084 buffer += num_digits;
1087 const char* digits = upper ?
"0123456789ABCDEF" : data::hex_digits;
1088 unsigned digit = (value & ((1 << BASE_BITS) - 1));
1089 *--buffer =
static_cast<Char
>(BASE_BITS < 4 ? static_cast<char>(
'0' + digit)
1091 }
while ((value >>= BASE_BITS) != 0);
1095 template <
unsigned BASE_BITS,
typename Char>
1098 auto char_digits = std::numeric_limits<unsigned char>::digits / 4;
1099 int start = (num_digits + char_digits - 1) / char_digits - 1;
1100 if (
int start_digits = num_digits % char_digits) {
1101 unsigned value = n.value[start--];
1102 buffer = format_uint<BASE_BITS>(
buffer, value, start_digits);
1104 for (; start >= 0; --start) {
1105 unsigned value = n.value[start];
1106 buffer += char_digits;
1108 for (
int i = 0; i < char_digits; ++i) {
1109 unsigned digit = (value & ((1 << BASE_BITS) - 1));
1110 *--p =
static_cast<Char
>(data::hex_digits[digit]);
1111 value >>= BASE_BITS;
1117 template <
unsigned BASE_BITS,
typename Char,
typename It,
typename UInt>
1118 inline It format_uint(It out, UInt value,
int num_digits,
bool upper =
false) {
1119 if (
auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
1120 format_uint<BASE_BITS>(ptr, value, num_digits, upper);
1124 char buffer[num_bits<UInt>() / BASE_BITS + 1];
1125 format_uint<BASE_BITS>(
buffer, value, num_digits, upper);
1126 return detail::copy_str<Char>(
buffer, buffer + num_digits, out);
1136 operator wstring_view()
const {
return {&buffer_[0], size()}; }
1137 size_t size()
const {
return buffer_.
size() - 1; }
1138 const wchar_t* c_str()
const {
return &buffer_[0]; }
1139 std::wstring str()
const {
return {&buffer_[0], size()}; }
1142 template <
typename T =
void>
struct null {};
1147 enum { max_size = 4 };
1148 Char data_[max_size] = {Char(
' '), Char(0), Char(0), Char(0)};
1149 unsigned char size_ = 1;
1153 auto size = s.
size();
1154 if (size > max_size) {
1158 for (
size_t i = 0; i < size; ++i) data_[i] = s[i];
1159 size_ =
static_cast<unsigned char>(size);
1162 size_t size()
const {
return size_; }
1163 const Char*
data()
const {
return data_; }
1165 FMT_CONSTEXPR Char& operator[](
size_t index) {
return data_[index]; }
1166 FMT_CONSTEXPR
const Char& operator[](
size_t index)
const {
1167 return data_[index];
1175 enum type { none, left, right, center, numeric };
1177 using align_t = align::type;
1180 enum type { none, minus, plus, space };
1182 using sign_t = sign::type;
1206 namespace dragonbox {
1212 using carrier_uint = uint32_t;
1213 static const int significand_bits = 23;
1214 static const int exponent_bits = 8;
1215 static const int min_exponent = -126;
1216 static const int max_exponent = 127;
1217 static const int exponent_bias = -127;
1218 static const int decimal_digits = 9;
1219 static const int kappa = 1;
1220 static const int big_divisor = 100;
1221 static const int small_divisor = 10;
1222 static const int min_k = -31;
1223 static const int max_k = 46;
1224 static const int cache_bits = 64;
1225 static const int divisibility_check_by_5_threshold = 39;
1226 static const int case_fc_pm_half_lower_threshold = -1;
1227 static const int case_fc_pm_half_upper_threshold = 6;
1228 static const int case_fc_lower_threshold = -2;
1229 static const int case_fc_upper_threshold = 6;
1230 static const int case_shorter_interval_left_endpoint_lower_threshold = 2;
1231 static const int case_shorter_interval_left_endpoint_upper_threshold = 3;
1232 static const int shorter_interval_tie_lower_threshold = -35;
1233 static const int shorter_interval_tie_upper_threshold = -35;
1234 static const int max_trailing_zeros = 7;
1238 using carrier_uint = uint64_t;
1239 static const int significand_bits = 52;
1240 static const int exponent_bits = 11;
1241 static const int min_exponent = -1022;
1242 static const int max_exponent = 1023;
1243 static const int exponent_bias = -1023;
1244 static const int decimal_digits = 17;
1245 static const int kappa = 2;
1246 static const int big_divisor = 1000;
1247 static const int small_divisor = 100;
1248 static const int min_k = -292;
1249 static const int max_k = 326;
1250 static const int cache_bits = 128;
1251 static const int divisibility_check_by_5_threshold = 86;
1252 static const int case_fc_pm_half_lower_threshold = -2;
1253 static const int case_fc_pm_half_upper_threshold = 9;
1254 static const int case_fc_lower_threshold = -4;
1255 static const int case_fc_upper_threshold = 9;
1256 static const int case_shorter_interval_left_endpoint_lower_threshold = 2;
1257 static const int case_shorter_interval_left_endpoint_upper_threshold = 3;
1258 static const int shorter_interval_tie_lower_threshold = -77;
1259 static const int shorter_interval_tie_upper_threshold = -77;
1260 static const int max_trailing_zeros = 16;
1265 significand_type significand;
1269 template <
typename T> FMT_API
decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT;
1272 template <
typename T>
1280 enum class float_format : unsigned char {
1289 float_format format : 8;
1299 template <
typename Char,
typename It> It write_exponent(
int exp, It it) {
1300 FMT_ASSERT(-10000 < exp && exp < 10000,
"exponent out of range");
1302 *it++ =
static_cast<Char
>(
'-');
1305 *it++ =
static_cast<Char
>(
'+');
1308 const char* top = data::digits[exp / 100];
1309 if (exp >= 1000) *it++ =
static_cast<Char
>(top[0]);
1310 *it++ =
static_cast<Char
>(top[1]);
1313 const char* d = data::digits[exp];
1314 *it++ =
static_cast<Char
>(d[0]);
1315 *it++ =
static_cast<Char
>(d[1]);
1319 template <
typename T>
1323 template <
typename T>
1324 int snprintf_float(T value,
int precision,
float_specs specs,
1327 template <
typename T> T promote_float(T value) {
return value; }
1328 inline double promote_float(
float value) {
return static_cast<double>(value); }
1330 template <
typename Handler>
1331 FMT_CONSTEXPR
void handle_int_type_spec(
char spec, Handler&& handler) {
1348 #ifdef FMT_DEPRECATED_N_SPECIFIER 1362 template <
typename ErrorHandler = error_handler,
typename Char>
1366 result.showpoint = specs.alt;
1367 switch (specs.type) {
1369 result.format = float_format::general;
1370 result.showpoint |= specs.precision > 0;
1373 result.upper =
true;
1376 result.format = float_format::general;
1379 result.upper =
true;
1382 result.format = float_format::exp;
1383 result.showpoint |= specs.precision != 0;
1386 result.upper =
true;
1389 result.format = float_format::fixed;
1390 result.showpoint |= specs.precision != 0;
1393 result.upper =
true;
1396 result.format = float_format::hex;
1398 #ifdef FMT_DEPRECATED_N_SPECIFIER 1402 result.locale =
true;
1405 eh.on_error(
"invalid type specifier");
1411 template <
typename Char,
typename Handler>
1413 Handler&& handler) {
1414 if (!specs)
return handler.on_char();
1415 if (specs->type && specs->type !=
'c')
return handler.on_int();
1416 if (specs->align == align::numeric || specs->sign != sign::none || specs->alt)
1417 handler.on_error(
"invalid format specifier for char");
1421 template <
typename Char,
typename Handler>
1422 FMT_CONSTEXPR
void handle_cstring_type_spec(Char spec, Handler&& handler) {
1423 if (spec == 0 || spec ==
's')
1424 handler.on_string();
1425 else if (spec ==
'p')
1426 handler.on_pointer();
1428 handler.on_error(
"invalid type specifier");
1431 template <
typename Char,
typename ErrorHandler>
1432 FMT_CONSTEXPR
void check_string_type_spec(Char spec, ErrorHandler&& eh) {
1433 if (spec != 0 && spec !=
's') eh.on_error(
"invalid type specifier");
1436 template <
typename Char,
typename ErrorHandler>
1437 FMT_CONSTEXPR
void check_pointer_type_spec(Char spec, ErrorHandler&& eh) {
1438 if (spec != 0 && spec !=
'p') eh.on_error(
"invalid type specifier");
1443 FMT_CONSTEXPR
explicit int_type_checker(ErrorHandler eh) : ErrorHandler(eh) {}
1445 FMT_CONSTEXPR
void on_dec() {}
1446 FMT_CONSTEXPR
void on_hex() {}
1447 FMT_CONSTEXPR
void on_bin() {}
1448 FMT_CONSTEXPR
void on_oct() {}
1449 FMT_CONSTEXPR
void on_num() {}
1450 FMT_CONSTEXPR
void on_chr() {}
1452 FMT_CONSTEXPR
void on_error() {
1453 ErrorHandler::on_error(
"invalid type specifier");
1457 template <
typename ErrorHandler>
1464 : ErrorHandler(eh), type_(type) {}
1466 FMT_CONSTEXPR
void on_int() {
1469 FMT_CONSTEXPR
void on_char() {}
1472 template <
typename ErrorHandler>
1476 : ErrorHandler(eh) {}
1478 FMT_CONSTEXPR
void on_string() {}
1479 FMT_CONSTEXPR
void on_pointer() {}
1482 template <
typename OutputIt,
typename Char>
1483 FMT_NOINLINE OutputIt fill(OutputIt it,
size_t n,
const fill_t<Char>& fill) {
1484 auto fill_size = fill.size();
1485 if (fill_size == 1)
return std::fill_n(it, n, fill[0]);
1486 for (
size_t i = 0; i < n; ++i) it = std::copy_n(fill.data(), fill_size, it);
1493 template <align::type
align = align::left,
typename OutputIt,
typename Char,
1495 inline OutputIt write_padded(OutputIt out,
1497 size_t width, F&& f) {
1498 static_assert(align == align::left || align == align::right,
"");
1499 unsigned spec_width = to_unsigned(specs.width);
1500 size_t padding = spec_width > width ? spec_width - width : 0;
1501 auto* shifts = align == align::left ? data::left_padding_shifts
1502 : data::right_padding_shifts;
1503 size_t left_padding = padding >> shifts[specs.align];
1504 auto it = reserve(out, size + padding * specs.fill.size());
1505 it = fill(it, left_padding, specs.fill);
1507 it = fill(it, padding - left_padding, specs.fill);
1508 return base_iterator(out, it);
1511 template <align::type align = align::left,
typename OutputIt,
typename Char,
1513 inline OutputIt write_padded(OutputIt out,
1516 return write_padded<align>(out, specs, size, size, f);
1519 template <
typename Char,
typename OutputIt>
1522 using iterator = remove_reference_t<decltype(reserve(out, 0))>;
1523 return write_padded(out, specs, bytes.
size(), [bytes](iterator it) {
1525 return copy_str<Char>(data, data + bytes.
size(), it);
1537 : size(prefix.
size() + to_unsigned(num_digits)), padding(0) {
1538 if (specs.align == align::numeric) {
1539 auto width = to_unsigned(specs.width);
1541 padding = width - size;
1544 }
else if (specs.precision > num_digits) {
1545 size = prefix.
size() + to_unsigned(specs.precision);
1546 padding = to_unsigned(specs.precision - num_digits);
1554 template <
typename OutputIt,
typename Char,
typename F>
1555 OutputIt write_int(OutputIt out,
int num_digits,
string_view prefix,
1558 using iterator = remove_reference_t<decltype(reserve(out, 0))>;
1559 return write_padded<align::right>(out, specs,
data.size, [=](iterator it) {
1560 if (prefix.size() != 0)
1561 it = copy_str<Char>(prefix.begin(), prefix.end(), it);
1562 it = std::fill_n(it,
data.padding, static_cast<Char>(
'0'));
1567 template <
typename StrChar,
typename Char,
typename OutputIt>
1571 auto size = s.
size();
1572 if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
1573 size = code_point_index(s, to_unsigned(specs.precision));
1574 auto width = specs.width != 0
1577 using iterator = remove_reference_t<decltype(reserve(out, 0))>;
1578 return write_padded(out, specs, size, width, [=](iterator it) {
1579 return copy_str<Char>(
data, data + size, it);
1584 template <
typename OutputIt,
typename Char,
typename UInt>
struct int_writer {
1590 unsigned prefix_size;
1593 remove_reference_t<decltype(reserve(std::declval<OutputIt&>(), 0))>;
1597 template <
typename Int>
1603 abs_value(static_cast<UInt>(value)),
1605 static_assert(std::is_same<uint32_or_64_or_128_t<Int>, UInt>::value,
"");
1606 if (is_negative(value)) {
1609 abs_value = 0 - abs_value;
1610 }
else if (specs.sign != sign::none && specs.sign != sign::minus) {
1611 prefix[0] = specs.sign == sign::plus ?
'+' :
' ';
1617 auto num_digits = count_digits(abs_value);
1619 out, num_digits, get_prefix(), specs, [
this, num_digits](iterator it) {
1620 return format_decimal<Char>(it, abs_value, num_digits).end;
1626 prefix[prefix_size++] =
'0';
1627 prefix[prefix_size++] = specs.type;
1629 int num_digits = count_digits<4>(abs_value);
1630 out = write_int(out, num_digits, get_prefix(), specs,
1631 [
this, num_digits](iterator it) {
1632 return format_uint<4, Char>(it, abs_value, num_digits,
1639 prefix[prefix_size++] =
'0';
1640 prefix[prefix_size++] =
static_cast<char>(specs.type);
1642 int num_digits = count_digits<1>(abs_value);
1643 out = write_int(out, num_digits, get_prefix(), specs,
1644 [
this, num_digits](iterator it) {
1645 return format_uint<1, Char>(it, abs_value, num_digits);
1650 int num_digits = count_digits<3>(abs_value);
1651 if (specs.alt && specs.precision <= num_digits && abs_value != 0) {
1654 prefix[prefix_size++] =
'0';
1656 out = write_int(out, num_digits, get_prefix(), specs,
1657 [
this, num_digits](iterator it) {
1658 return format_uint<3, Char>(it, abs_value, num_digits);
1662 enum { sep_size = 1 };
1665 std::string groups = grouping<Char>(locale);
1666 if (groups.empty())
return on_dec();
1667 auto sep = thousands_sep<Char>(locale);
1668 if (!sep)
return on_dec();
1669 int num_digits = count_digits(abs_value);
1670 int size = num_digits, n = num_digits;
1671 std::string::const_iterator group = groups.cbegin();
1672 while (group != groups.cend() && n > *group && *group > 0 &&
1673 *group != max_value<char>()) {
1678 if (group == groups.cend()) size += sep_size * ((n - 1) / groups.back());
1680 format_decimal(digits, abs_value, num_digits);
1682 size +=
static_cast<int>(prefix_size);
1683 const auto usize = to_unsigned(size);
1687 int digit_index = 0;
1688 group = groups.cbegin();
1689 auto p = buffer.
data() + size - 1;
1690 for (
int i = num_digits - 1; i > 0; --i) {
1691 *p-- =
static_cast<Char
>(digits[i]);
1692 if (*group <= 0 || ++digit_index % *group != 0 ||
1693 *group == max_value<char>())
1695 if (group + 1 != groups.cend()) {
1700 make_checked(p, s.
size()));
1703 *p-- =
static_cast<Char
>(*digits);
1704 if (prefix_size != 0) *p =
static_cast<Char
>(
'-');
1706 out = write_padded<align::right>(
1707 out, specs, usize, usize,
1708 [=](iterator it) {
return copy_str<Char>(
data, data + size, it); });
1711 void on_chr() { *out++ =
static_cast<Char
>(abs_value); }
1713 FMT_NORETURN
void on_error() {
1718 template <
typename Char,
typename OutputIt>
1719 OutputIt write_nonfinite(OutputIt out,
bool isinf,
1723 isinf ? (fspecs.upper ?
"INF" :
"inf") : (fspecs.upper ?
"NAN" :
"nan");
1724 constexpr
size_t str_size = 3;
1725 auto sign = fspecs.sign;
1726 auto size = str_size + (
sign ? 1 : 0);
1727 using iterator = remove_reference_t<decltype(reserve(out, 0))>;
1728 return write_padded(out, specs, size, [=](iterator it) {
1729 if (
sign) *it++ = static_cast<Char>(data::signs[
sign]);
1730 return copy_str<Char>(str, str + str_size, it);
1736 const char* significand;
1737 int significand_size;
1742 return fp.significand_size;
1744 template <
typename T>
1746 return count_digits(fp.significand);
1749 template <
typename Char,
typename OutputIt>
1750 inline OutputIt write_significand(OutputIt out,
const char* significand,
1751 int& significand_size) {
1752 return copy_str<Char>(significand, significand + significand_size, out);
1754 template <
typename Char,
typename OutputIt,
typename UInt>
1755 inline OutputIt write_significand(OutputIt out, UInt significand,
1756 int significand_size) {
1757 return format_decimal<Char>(out, significand, significand_size).end;
1760 template <
typename Char,
typename UInt,
1761 FMT_ENABLE_IF(std::is_integral<UInt>::value)>
1762 inline Char* write_significand(Char* out, UInt significand,
1763 int significand_size,
int integral_size,
1764 Char decimal_point) {
1766 return format_decimal(out, significand, significand_size).end;
1767 auto end = format_decimal(out + 1, significand, significand_size).end;
1768 if (integral_size == 1)
1771 std::copy_n(out + 1, integral_size, out);
1772 out[integral_size] = decimal_point;
1776 template <
typename OutputIt,
typename UInt,
typename Char,
1777 FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)>
1778 inline OutputIt write_significand(OutputIt out, UInt significand,
1779 int significand_size,
int integral_size,
1780 Char decimal_point) {
1782 Char
buffer[digits10<UInt>() + 2];
1783 auto end = write_significand(
buffer, significand, significand_size,
1784 integral_size, decimal_point);
1785 return detail::copy_str<Char>(
buffer, end, out);
1788 template <
typename OutputIt,
typename Char>
1789 inline OutputIt write_significand(OutputIt out,
const char* significand,
1790 int significand_size,
int integral_size,
1791 Char decimal_point) {
1792 out = detail::copy_str<Char>(significand, significand + integral_size, out);
1793 if (!decimal_point)
return out;
1794 *out++ = decimal_point;
1795 return detail::copy_str<Char>(significand + integral_size,
1796 significand + significand_size, out);
1799 template <
typename OutputIt,
typename DecimalFP,
typename Char>
1800 OutputIt write_float(OutputIt out,
const DecimalFP& fp,
1802 Char decimal_point) {
1803 auto significand = fp.significand;
1804 int significand_size = get_significand_size(fp);
1805 static const Char zero =
static_cast<Char
>(
'0');
1806 auto sign = fspecs.sign;
1807 size_t size = to_unsigned(significand_size) + (
sign ? 1 : 0);
1808 using iterator = remove_reference_t<decltype(reserve(out, 0))>;
1810 int output_exp = fp.exponent + significand_size - 1;
1811 auto use_exp_format = [=]() {
1812 if (fspecs.format == float_format::exp)
return true;
1813 if (fspecs.format != float_format::general)
return false;
1816 const int exp_lower = -4, exp_upper = 16;
1817 return output_exp < exp_lower ||
1818 output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper);
1820 if (use_exp_format()) {
1822 if (fspecs.showpoint) {
1823 num_zeros = (std::max)(fspecs.precision - significand_size, 0);
1824 size += to_unsigned(num_zeros);
1825 }
else if (significand_size == 1) {
1826 decimal_point = Char();
1828 auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp;
1830 if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3;
1832 size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits);
1833 char exp_char = fspecs.upper ?
'E' :
'e';
1834 auto write = [=](iterator it) {
1835 if (
sign) *it++ =
static_cast<Char
>(data::signs[
sign]);
1837 it = write_significand(it, significand, significand_size, 1,
1839 if (num_zeros > 0) it = std::fill_n(it, num_zeros, zero);
1840 *it++ =
static_cast<Char
>(exp_char);
1841 return write_exponent<Char>(output_exp, it);
1843 return specs.width > 0 ? write_padded<align::right>(out, specs, size,
write)
1844 : base_iterator(out,
write(reserve(out, size)));
1847 int exp = fp.exponent + significand_size;
1848 if (fp.exponent >= 0) {
1850 size += to_unsigned(fp.exponent);
1851 int num_zeros = fspecs.precision - exp;
1853 if (num_zeros > 5000)
1854 throw std::runtime_error(
"fuzz mode - avoiding excessive cpu use");
1856 if (fspecs.showpoint) {
1857 if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 1;
1858 if (num_zeros > 0) size += to_unsigned(num_zeros);
1860 return write_padded<align::right>(out, specs, size, [&](iterator it) {
1861 if (
sign) *it++ =
static_cast<Char
>(data::signs[
sign]);
1862 it = write_significand<Char>(it, significand, significand_size);
1863 it = std::fill_n(it, fp.exponent, zero);
1864 if (!fspecs.showpoint)
return it;
1865 *it++ = decimal_point;
1866 return num_zeros > 0 ? std::fill_n(it, num_zeros, zero) : it;
1868 }
else if (exp > 0) {
1870 int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0;
1871 size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0);
1872 return write_padded<align::right>(out, specs, size, [&](iterator it) {
1873 if (
sign) *it++ =
static_cast<Char
>(data::signs[
sign]);
1874 it = write_significand(it, significand, significand_size, exp,
1876 return num_zeros > 0 ? std::fill_n(it, num_zeros, zero) : it;
1880 int num_zeros = -exp;
1881 if (significand_size == 0 && fspecs.precision >= 0 &&
1882 fspecs.precision < num_zeros) {
1883 num_zeros = fspecs.precision;
1885 size += 2 + to_unsigned(num_zeros);
1886 return write_padded<align::right>(out, specs, size, [&](iterator it) {
1887 if (
sign) *it++ =
static_cast<Char
>(data::signs[
sign]);
1889 if (num_zeros == 0 && significand_size == 0 && !fspecs.showpoint)
return it;
1890 *it++ = decimal_point;
1891 it = std::fill_n(it, num_zeros, zero);
1892 return write_significand<Char>(it, significand, significand_size);
1896 template <
typename Char,
typename OutputIt,
typename T,
1897 FMT_ENABLE_IF(std::is_floating_point<T>::value)>
1900 if (const_check(!is_supported_floating_point(value)))
return out;
1901 float_specs fspecs = parse_float_type_spec(specs);
1902 fspecs.sign = specs.sign;
1903 if (std::signbit(value)) {
1904 fspecs.sign = sign::minus;
1906 }
else if (fspecs.sign == sign::minus) {
1907 fspecs.sign = sign::none;
1910 if (!std::isfinite(value))
1911 return write_nonfinite(out, std::isinf(value), specs, fspecs);
1913 if (specs.align == align::numeric && fspecs.sign) {
1914 auto it = reserve(out, 1);
1915 *it++ =
static_cast<Char
>(data::signs[fspecs.sign]);
1916 out = base_iterator(out, it);
1917 fspecs.sign = sign::none;
1918 if (specs.width != 0) --specs.width;
1922 if (fspecs.format == float_format::hex) {
1923 if (fspecs.sign) buffer.push_back(data::signs[fspecs.sign]);
1924 snprintf_float(promote_float(value), specs.precision, fspecs, buffer);
1925 return write_bytes(out, {buffer.
data(), buffer.
size()}, specs);
1927 int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6;
1928 if (fspecs.format == float_format::exp) {
1929 if (precision == max_value<int>())
1934 if (const_check(std::is_same<T, float>())) fspecs.binary32 =
true;
1935 fspecs.use_grisu = is_fast_float<T>();
1936 int exp = format_float(promote_float(value), precision, fspecs, buffer);
1937 fspecs.precision = precision;
1939 fspecs.locale ? decimal_point<Char>(loc) : static_cast<Char>(
'.');
1941 return write_float(out, fp, specs, fspecs, point);
1944 template <
typename Char,
typename OutputIt,
typename T,
1945 FMT_ENABLE_IF(is_fast_float<T>::value)>
1946 OutputIt
write(OutputIt out, T value) {
1947 if (const_check(!is_supported_floating_point(value)))
return out;
1949 using floaty = conditional_t<std::is_same<T, long double>::value, double, T>;
1951 auto bits = bit_cast<uint>(value);
1954 auto sign_bit =
bits & (uint(1) << (num_bits<uint>() - 1));
1955 if (sign_bit != 0) {
1956 fspecs.sign = sign::minus;
1961 uint mask = exponent_mask<floaty>();
1962 if ((
bits & mask) == mask)
1963 return write_nonfinite(out, std::isinf(value), specs, fspecs);
1965 auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
1966 return write_float(out, dec, specs, fspecs, static_cast<Char>(
'.'));
1969 template <
typename Char,
typename OutputIt,
typename T,
1970 FMT_ENABLE_IF(std::is_floating_point<T>::value &&
1971 !is_fast_float<T>::value)>
1972 inline OutputIt
write(OutputIt out, T value) {
1976 template <
typename Char,
typename OutputIt>
1977 OutputIt write_char(OutputIt out, Char value,
1979 using iterator = remove_reference_t<decltype(reserve(out, 0))>;
1980 return write_padded(out, specs, 1, [=](iterator it) {
1986 template <
typename Char,
typename OutputIt,
typename UIntPtr>
1987 OutputIt write_ptr(OutputIt out, UIntPtr value,
1989 int num_digits = count_digits<4>(value);
1990 auto size = to_unsigned(num_digits) + size_t(2);
1991 using iterator = remove_reference_t<decltype(reserve(out, 0))>;
1992 auto write = [=](iterator it) {
1993 *it++ =
static_cast<Char
>(
'0');
1994 *it++ =
static_cast<Char
>(
'x');
1995 return format_uint<4, Char>(it, value, num_digits);
1997 return specs ? write_padded<align::right>(out, *specs, size,
write)
1998 : base_iterator(out,
write(reserve(out, size)));
2005 template <
typename Char,
typename OutputIt>
2007 FMT_ASSERT(
false,
"");
2011 template <
typename Char,
typename OutputIt,
2012 FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
2014 auto it = reserve(out, value.
size());
2015 it = copy_str<Char>(value.begin(), value.end(), it);
2016 return base_iterator(out, it);
2019 template <
typename Char,
typename OutputIt>
2021 auto it = reserve(out, value.
size());
2022 it = std::copy(value.begin(), value.end(), it);
2023 return base_iterator(out, it);
2026 template <
typename Char>
2029 get_container(out).append(value.begin(), value.end());
2033 template <
typename Char,
typename OutputIt,
typename T,
2035 !std::is_same<T, bool>::value &&
2036 !std::is_same<T, Char>::value)>
2037 OutputIt
write(OutputIt out, T value) {
2038 auto abs_value =
static_cast<uint32_or_64_or_128_t<T>
>(value);
2039 bool negative = is_negative(value);
2041 if (negative) abs_value = ~abs_value + 1;
2042 int num_digits = count_digits(abs_value);
2043 auto size = (negative ? 1 : 0) + static_cast<size_t>(num_digits);
2044 auto it = reserve(out, size);
2045 if (
auto ptr = to_pointer<Char>(it, size)) {
2046 if (negative) *ptr++ =
static_cast<Char
>(
'-');
2047 format_decimal<Char>(ptr, abs_value, num_digits);
2050 if (negative) *it++ =
static_cast<Char
>(
'-');
2051 it = format_decimal<Char>(it, abs_value, num_digits).end;
2052 return base_iterator(out, it);
2055 template <
typename Char,
typename OutputIt>
2056 OutputIt
write(OutputIt out,
bool value) {
2057 return write<Char>(out,
string_view(value ?
"true" :
"false"));
2060 template <
typename Char,
typename OutputIt>
2061 OutputIt
write(OutputIt out, Char value) {
2062 auto it = reserve(out, 1);
2064 return base_iterator(out, it);
2067 template <
typename Char,
typename OutputIt>
2068 OutputIt
write(OutputIt out,
const Char* value) {
2072 auto length = std::char_traits<Char>::length(value);
2078 template <
typename Char,
typename OutputIt>
2079 OutputIt
write(OutputIt out,
const void* value) {
2080 return write_ptr<Char>(out, to_uintptr(value),
nullptr);
2083 template <
typename Char,
typename OutputIt,
typename T>
2084 auto write(OutputIt out,
const T& value) ->
typename std::enable_if<
2089 using formatter_type =
2090 conditional_t<has_formatter<T, context_type>::value,
2091 typename context_type::template formatter_type<T>,
2093 context_type ctx(out, {}, {});
2094 return formatter_type().format(value, ctx);
2106 template <
typename T> OutputIt operator()(T value) {
2107 return write<Char>(out, value);
2113 handle.format(parse_ctx, format_ctx);
2114 return format_ctx.out();
2118 template <
typename OutputIt,
typename Char,
2122 using iterator = OutputIt;
2123 using char_type = Char;
2133 auto reserve(
size_t n) -> decltype(detail::reserve(out_, n)) {
2134 return detail::reserve(out_, n);
2137 using reserve_iterator = remove_reference_t<decltype(
2138 detail::reserve(std::declval<iterator&>(), 0))>;
2140 template <
typename T>
void write_int(T value,
const format_specs& spec) {
2141 using uint_type = uint32_or_64_or_128_t<T>;
2143 handle_int_type_spec(spec.type, w);
2147 void write(
char value) {
2148 auto&& it = reserve(1);
2152 template <typename Ch, FMT_ENABLE_IF(std::is_same<Ch, Char>::value)>
2153 void write(Ch value) {
2154 out_ = detail::write<Char>(out_, value);
2158 auto&& it = reserve(value.
size());
2159 it = copy_str<Char>(value.begin(), value.end(), it);
2162 static_assert(std::is_same<Char, wchar_t>::value,
"");
2163 auto&& it = reserve(value.
size());
2164 it = std::copy(value.begin(), value.end(), it);
2167 template <
typename Ch>
2169 auto width = specs.width != 0
2172 out_ = write_padded(out_, specs, size, width, [=](reserve_iterator it) {
2173 return copy_str<Char>(s, s + size, it);
2177 template <
typename Ch>
2182 void write_pointer(
const void* p) {
2183 out_ = write_ptr<char_type>(out_, to_uintptr(p), specs_);
2186 struct char_spec_handler : ErrorHandler {
2191 : formatter(f), value(val) {}
2195 formatter.write_int(static_cast<int>(value), *formatter.specs_);
2198 if (formatter.specs_)
2199 formatter.out_ = write_char(formatter.out_, value, *formatter.specs_);
2201 formatter.write(value);
2210 : formatter(f), value(val) {}
2212 void on_string() { formatter.write(value); }
2213 void on_pointer() { formatter.write_pointer(value); }
2217 iterator out() {
return out_; }
2220 void write(
bool value) {
2224 out_ = detail::write<Char>(out_, value);
2227 void write(
const Char* value) {
2231 auto length = std::char_traits<char_type>::length(value);
2239 : out_(out), locale_(loc), specs_(s) {}
2242 FMT_ASSERT(
false,
"invalid argument type");
2246 template <typename T, FMT_ENABLE_IF(is_integral<T>::value)>
2247 FMT_INLINE iterator
operator()(T value) {
2249 write_int(value, *specs_);
2251 out_ = detail::write<Char>(out_, value);
2255 iterator operator()(Char value) {
2256 handle_char_specs(specs_,
2257 char_spec_handler(*
this, static_cast<Char>(value)));
2261 iterator operator()(
bool value) {
2262 if (specs_ && specs_->type)
return (*
this)(value ? 1 : 0);
2267 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
2268 iterator
operator()(T value) {
2270 if (const_check(is_supported_floating_point(value)))
2273 FMT_ASSERT(
false,
"unsupported float argument type");
2277 iterator operator()(
const Char* value) {
2278 if (!specs_)
return write(value), out_;
2279 handle_cstring_type_spec(specs_->type, cstring_spec_handler(*
this, value));
2286 write(value, *specs_);
2293 iterator operator()(
const void* value) {
2294 if (specs_) check_pointer_type_spec(specs_->type,
error_handler());
2295 write_pointer(value);
2301 template <
typename OutputIt,
typename Char>
2304 using char_type = Char;
2313 using iterator =
typename base::iterator;
2326 format_specs* specs =
nullptr,
const Char* ptr =
nullptr)
2327 :
base(ctx.out(), specs, ctx.locale()),
2329 parse_ctx_(parse_ctx),
2332 using base::operator();
2336 if (ptr_) advance_to(*parse_ctx_, ptr_);
2337 handle.format(*parse_ctx_, ctx_);
2342 template <
typename Char> FMT_CONSTEXPR
bool is_name_start(Char c) {
2343 return (
'a' <= c && c <=
'z') || (
'A' <= c && c <=
'Z') ||
'_' == c;
2348 template <
typename Char,
typename ErrorHandler>
2349 FMT_CONSTEXPR
int parse_nonnegative_int(
const Char*& begin,
const Char* end,
2350 ErrorHandler&& eh) {
2351 FMT_ASSERT(begin != end &&
'0' <= *begin && *begin <=
'9',
"");
2354 constexpr
unsigned max_int = max_value<int>();
2355 unsigned big = max_int / 10;
2359 value = max_int + 1;
2362 value = value * 10 + unsigned(*begin -
'0');
2364 }
while (begin != end &&
'0' <= *begin && *begin <=
'9');
2365 if (value > max_int) eh.on_error(
"number is too big");
2366 return static_cast<int>(value);
2371 using char_type =
typename Context::char_type;
2379 : parse_ctx_(parse_ctx), ctx_(ctx) {}
2382 h.format(parse_ctx_, ctx_);
2385 template <
typename T>
void operator()(T)
const {}
2388 template <
typename T>
2390 bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value &&
2391 !std::is_same<T, char>::value &&
2392 !std::is_same<T, wchar_t>::value>;
2396 explicit FMT_CONSTEXPR
width_checker(ErrorHandler& eh) : handler_(eh) {}
2398 template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
2399 FMT_CONSTEXPR
unsigned long long operator()(T value) {
2400 if (is_negative(value)) handler_.on_error(
"negative width");
2401 return static_cast<unsigned long long>(value);
2404 template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
2405 FMT_CONSTEXPR
unsigned long long operator()(T) {
2406 handler_.on_error(
"width is not integer");
2411 ErrorHandler& handler_;
2418 template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
2419 FMT_CONSTEXPR
unsigned long long operator()(T value) {
2420 if (is_negative(value)) handler_.on_error(
"negative precision");
2421 return static_cast<unsigned long long>(value);
2424 template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
2425 FMT_CONSTEXPR
unsigned long long operator()(T) {
2426 handler_.on_error(
"precision is not integer");
2431 ErrorHandler& handler_;
2440 FMT_CONSTEXPR specs_setter(
const specs_setter& other)
2441 : specs_(other.specs_) {}
2443 FMT_CONSTEXPR
void on_align(align_t align) { specs_.align = align; }
2447 FMT_CONSTEXPR
void on_plus() { specs_.sign = sign::plus; }
2448 FMT_CONSTEXPR
void on_minus() { specs_.sign = sign::minus; }
2449 FMT_CONSTEXPR
void on_space() { specs_.sign = sign::space; }
2450 FMT_CONSTEXPR
void on_hash() { specs_.alt =
true; }
2452 FMT_CONSTEXPR
void on_zero() {
2453 specs_.align = align::numeric;
2454 specs_.fill[0] = Char(
'0');
2457 FMT_CONSTEXPR
void on_width(
int width) { specs_.width = width; }
2458 FMT_CONSTEXPR
void on_precision(
int precision) {
2459 specs_.precision = precision;
2461 FMT_CONSTEXPR
void end_precision() {}
2463 FMT_CONSTEXPR
void on_type(Char type) {
2464 specs_.type =
static_cast<char>(type);
2474 : error_handler_(eh), arg_type_(arg_type) {}
2476 FMT_CONSTEXPR
void require_numeric_argument() {
2477 if (!is_arithmetic_type(arg_type_))
2478 error_handler_.on_error(
"format specifier requires numeric argument");
2481 FMT_CONSTEXPR
void check_sign() {
2482 require_numeric_argument();
2483 if (is_integral_type(arg_type_) && arg_type_ != type::int_type &&
2484 arg_type_ != type::long_long_type && arg_type_ != type::char_type) {
2485 error_handler_.on_error(
"format specifier requires signed argument");
2489 FMT_CONSTEXPR
void check_precision() {
2490 if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type)
2491 error_handler_.on_error(
"precision not allowed for this argument type");
2495 ErrorHandler& error_handler_;
2496 detail::type arg_type_;
2509 FMT_CONSTEXPR
specs_checker(
const Handler& handler, detail::type arg_type)
2512 FMT_CONSTEXPR specs_checker(
const specs_checker& other)
2513 : Handler(other), checker_(
error_handler(), other.arg_type_) {}
2515 FMT_CONSTEXPR
void on_align(align_t align) {
2516 if (align == align::numeric) checker_.require_numeric_argument();
2517 Handler::on_align(align);
2520 FMT_CONSTEXPR
void on_plus() {
2521 checker_.check_sign();
2525 FMT_CONSTEXPR
void on_minus() {
2526 checker_.check_sign();
2527 Handler::on_minus();
2530 FMT_CONSTEXPR
void on_space() {
2531 checker_.check_sign();
2532 Handler::on_space();
2535 FMT_CONSTEXPR
void on_hash() {
2536 checker_.require_numeric_argument();
2540 FMT_CONSTEXPR
void on_zero() {
2541 checker_.require_numeric_argument();
2545 FMT_CONSTEXPR
void end_precision() { checker_.check_precision(); }
2548 template <
template <
typename>
class Handler,
typename FormatArg,
2549 typename ErrorHandler>
2550 FMT_CONSTEXPR
int get_dynamic_spec(FormatArg arg, ErrorHandler eh) {
2551 unsigned long long value = visit_format_arg(Handler<ErrorHandler>(eh), arg);
2552 if (value > to_unsigned(max_value<int>())) eh.on_error(
"number is too big");
2553 return static_cast<int>(value);
2558 template <
typename Context,
typename ID>
2559 FMT_CONSTEXPR
typename Context::format_arg get_arg(Context& ctx, ID
id) {
2560 auto arg = ctx.arg(
id);
2561 if (!arg) ctx.on_error(
"argument not found");
2566 template <
typename ParseContext,
typename Context>
2569 using char_type =
typename Context::char_type;
2572 ParseContext& parse_ctx, Context& ctx)
2574 parse_context_(parse_ctx),
2577 template <
typename Id> FMT_CONSTEXPR
void on_dynamic_width(Id arg_id) {
2578 this->specs_.width = get_dynamic_spec<width_checker>(
2579 get_arg(arg_id), context_.error_handler());
2582 template <
typename Id> FMT_CONSTEXPR
void on_dynamic_precision(Id arg_id) {
2583 this->specs_.precision = get_dynamic_spec<precision_checker>(
2584 get_arg(arg_id), context_.error_handler());
2587 void on_error(
const char* message) { context_.on_error(message); }
2591 using format_arg =
typename Context::format_arg;
2593 FMT_CONSTEXPR format_arg get_arg(
auto_id) {
2594 return detail::get_arg(context_, parse_context_.next_arg_id());
2597 FMT_CONSTEXPR format_arg get_arg(
int arg_id) {
2598 parse_context_.check_arg_id(arg_id);
2599 return detail::get_arg(context_, arg_id);
2603 parse_context_.check_arg_id(arg_id);
2604 return detail::get_arg(context_, arg_id);
2607 ParseContext& parse_context_;
2611 enum class arg_id_kind { none, index, name };
2615 FMT_CONSTEXPR
arg_ref() : kind(arg_id_kind::none), val() {}
2617 FMT_CONSTEXPR
explicit arg_ref(
int index)
2618 : kind(arg_id_kind::index), val(index) {}
2620 : kind(arg_id_kind::name), val(name) {}
2622 FMT_CONSTEXPR arg_ref& operator=(
int idx) {
2623 kind = arg_id_kind::index;
2630 FMT_CONSTEXPR value(
int id = 0) : index{
id} {}
2641 template <
typename Char>
2649 template <
typename ParseContext>
2651 :
public specs_setter<typename ParseContext::char_type> {
2653 using char_type =
typename ParseContext::char_type;
2659 FMT_CONSTEXPR dynamic_specs_handler(
const dynamic_specs_handler& other)
2661 specs_(other.specs_),
2662 context_(other.context_) {}
2664 template <
typename Id> FMT_CONSTEXPR
void on_dynamic_width(Id arg_id) {
2665 specs_.width_ref = make_arg_ref(arg_id);
2668 template <
typename Id> FMT_CONSTEXPR
void on_dynamic_precision(Id arg_id) {
2669 specs_.precision_ref = make_arg_ref(arg_id);
2672 FMT_CONSTEXPR
void on_error(
const char* message) {
2673 context_.on_error(message);
2680 context_.check_arg_id(arg_id);
2689 context_.check_arg_id(arg_id);
2691 context_.begin(), to_unsigned(context_.end() - context_.begin()));
2696 ParseContext& context_;
2699 template <
typename Char,
typename IDHandler>
2700 FMT_CONSTEXPR
const Char* parse_arg_id(
const Char* begin,
const Char* end,
2701 IDHandler&& handler) {
2702 FMT_ASSERT(begin != end,
"");
2704 if (c ==
'}' || c ==
':') {
2708 if (c >=
'0' && c <=
'9') {
2711 index = parse_nonnegative_int(begin, end, handler);
2714 if (begin == end || (*begin !=
'}' && *begin !=
':'))
2715 handler.on_error(
"invalid format string");
2720 if (!is_name_start(c)) {
2721 handler.on_error(
"invalid format string");
2727 }
while (it != end && (is_name_start(c = *it) || (
'0' <= c && c <=
'9')));
2734 explicit FMT_CONSTEXPR
width_adapter(SpecHandler& h) : handler(h) {}
2736 FMT_CONSTEXPR
void operator()() { handler.on_dynamic_width(
auto_id()); }
2737 FMT_CONSTEXPR
void operator()(
int id) { handler.on_dynamic_width(
id); }
2739 handler.on_dynamic_width(
id);
2742 FMT_CONSTEXPR
void on_error(
const char* message) {
2743 handler.on_error(message);
2746 SpecHandler& handler;
2753 FMT_CONSTEXPR
void operator()() { handler.on_dynamic_precision(
auto_id()); }
2754 FMT_CONSTEXPR
void operator()(
int id) { handler.on_dynamic_precision(
id); }
2756 handler.on_dynamic_precision(
id);
2759 FMT_CONSTEXPR
void on_error(
const char* message) {
2760 handler.on_error(message);
2763 SpecHandler& handler;
2766 template <
typename Char>
2767 FMT_CONSTEXPR
int code_point_length(
const Char* begin) {
2768 if (const_check(
sizeof(Char) != 1))
return 1;
2769 constexpr
char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2770 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0};
2771 int len = lengths[
static_cast<unsigned char>(*begin) >> 3];
2779 template <
typename Char> constexpr
bool is_ascii_letter(Char c) {
2780 return (c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z');
2784 template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
2785 constexpr Char to_ascii(Char value) {
2788 template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)>
2789 constexpr
typename std::underlying_type<Char>::type to_ascii(Char value) {
2794 template <
typename Char,
typename Handler>
2795 FMT_CONSTEXPR
const Char* parse_align(
const Char* begin,
const Char* end,
2796 Handler&& handler) {
2797 FMT_ASSERT(begin != end,
"");
2798 auto align = align::none;
2799 auto p = begin + code_point_length(begin);
2800 if (p >= end) p = begin;
2802 switch (to_ascii(*p)) {
2804 align = align::left;
2807 align = align::right;
2809 #if FMT_DEPRECATED_NUMERIC_ALIGN 2811 align = align::numeric;
2815 align = align::center;
2818 if (align != align::none) {
2822 return handler.on_error(
"invalid fill character '{'"), begin;
2827 handler.on_align(align);
2829 }
else if (p == begin) {
2837 template <
typename Char,
typename Handler>
2838 FMT_CONSTEXPR
const Char* parse_width(
const Char* begin,
const Char* end,
2839 Handler&& handler) {
2840 FMT_ASSERT(begin != end,
"");
2841 if (
'0' <= *begin && *begin <=
'9') {
2842 handler.on_width(parse_nonnegative_int(begin, end, handler));
2843 }
else if (*begin ==
'{') {
2847 if (begin == end || *begin !=
'}')
2848 return handler.on_error(
"invalid format string"), begin;
2854 template <
typename Char,
typename Handler>
2855 FMT_CONSTEXPR
const Char* parse_precision(
const Char* begin,
const Char* end,
2856 Handler&& handler) {
2858 auto c = begin != end ? *begin : Char();
2859 if (
'0' <= c && c <=
'9') {
2860 handler.on_precision(parse_nonnegative_int(begin, end, handler));
2861 }
else if (c ==
'{') {
2867 if (begin == end || *begin++ !=
'}')
2868 return handler.on_error(
"invalid format string"), begin;
2870 return handler.on_error(
"missing precision specifier"), begin;
2872 handler.end_precision();
2878 template <
typename Char,
typename SpecHandler>
2879 FMT_CONSTEXPR
const Char* parse_format_specs(
const Char* begin,
const Char* end,
2880 SpecHandler&& handler) {
2881 if (begin == end)
return begin;
2883 begin = parse_align(begin, end, handler);
2884 if (begin == end)
return begin;
2887 switch (to_ascii(*begin)) {
2901 if (begin == end)
return begin;
2903 if (*begin ==
'#') {
2905 if (++begin == end)
return begin;
2909 if (*begin ==
'0') {
2911 if (++begin == end)
return begin;
2914 begin = parse_width(begin, end, handler);
2915 if (begin == end)
return begin;
2918 if (*begin ==
'.') {
2919 begin = parse_precision(begin, end, handler);
2923 if (begin != end && *begin !=
'}') handler.on_type(*begin++);
2928 template <
bool IS_CONSTEXPR,
typename T,
typename Ptr = const T*>
2929 FMT_CONSTEXPR
bool find(Ptr first, Ptr last, T value, Ptr& out) {
2930 for (out = first; out != last; ++out) {
2931 if (*out == value)
return true;
2937 inline bool find<false, char>(
const char* first,
const char* last,
char value,
2939 out =
static_cast<const char*
>(
2940 std::memchr(first, value, detail::to_unsigned(last - first)));
2941 return out !=
nullptr;
2948 FMT_CONSTEXPR
void operator()() { arg_id = handler.on_arg_id(); }
2949 FMT_CONSTEXPR
void operator()(
int id) { arg_id = handler.on_arg_id(
id); }
2951 arg_id = handler.on_arg_id(
id);
2953 FMT_CONSTEXPR
void on_error(
const char* message) {
2954 handler.on_error(message);
2958 template <
typename Char,
typename Handler>
2959 FMT_CONSTEXPR
const Char* parse_replacement_field(
const Char* begin,
2961 Handler&& handler) {
2963 if (begin == end)
return handler.on_error(
"invalid format string"), end;
2964 if (*begin ==
'}') {
2965 handler.on_replacement_field(handler.on_arg_id(), begin);
2966 }
else if (*begin ==
'{') {
2967 handler.on_text(begin, begin + 1);
2970 begin = parse_arg_id(begin, end, adapter);
2971 Char c = begin != end ? *begin : Char();
2973 handler.on_replacement_field(adapter.arg_id, begin);
2974 }
else if (c ==
':') {
2975 begin = handler.on_format_specs(adapter.arg_id, begin + 1, end);
2976 if (begin == end || *begin !=
'}')
2977 return handler.on_error(
"unknown format specifier"), end;
2979 return handler.on_error(
"missing '}' in format string"), end;
2985 template <
bool IS_CONSTEXPR,
typename Char,
typename Handler>
2986 FMT_CONSTEXPR_DECL FMT_INLINE
void parse_format_string(
2988 auto begin = format_str.
data();
2989 auto end = begin + format_str.
size();
2990 if (end - begin < 32) {
2992 const Char* p = begin;
2996 handler.on_text(begin, p - 1);
2997 begin = p = parse_replacement_field(p - 1, end, handler);
2998 }
else if (c ==
'}') {
2999 if (p == end || *p !=
'}')
3000 return handler.on_error(
"unmatched '}' in format string");
3001 handler.on_text(begin, p);
3005 handler.on_text(begin, end);
3009 FMT_CONSTEXPR
void operator()(
const Char* pbegin,
const Char* pend) {
3010 if (pbegin == pend)
return;
3012 const Char* p =
nullptr;
3013 if (!find<IS_CONSTEXPR>(pbegin, pend,
'}', p))
3014 return handler_.on_text(pbegin, pend);
3016 if (p == pend || *p !=
'}')
3017 return handler_.on_error(
"unmatched '}' in format string");
3018 handler_.on_text(pbegin, p);
3024 while (begin != end) {
3027 const Char* p = begin;
3028 if (*begin !=
'{' && !find<IS_CONSTEXPR>(begin + 1, end,
'{', p))
3029 return write(begin, end);
3031 begin = parse_replacement_field(p, end, handler);
3035 template <
typename T,
typename ParseContext>
3036 FMT_CONSTEXPR
const typename ParseContext::char_type* parse_format_specs(
3037 ParseContext& ctx) {
3038 using char_type =
typename ParseContext::char_type;
3041 conditional_t<detail::mapped_type_constant<T, context>::value !=
3044 auto f = conditional_t<has_formatter<mapped_type, context>::value,
3047 return f.parse(ctx);
3050 template <
typename OutputIt,
typename Char,
typename Context>
3057 : parse_context(str), context(out, format_args, loc) {}
3059 void on_text(
const Char* begin,
const Char* end) {
3060 auto size = to_unsigned(end - begin);
3061 auto out = context.out();
3062 auto&& it = reserve(out, size);
3063 it = std::copy_n(begin, size, it);
3064 context.advance_to(out);
3067 int on_arg_id() {
return parse_context.
next_arg_id(); }
3068 int on_arg_id(
int id) {
return parse_context.
check_arg_id(
id), id; }
3070 int arg_id = context.arg_id(
id);
3071 if (arg_id < 0) on_error(
"argument not found");
3075 FMT_INLINE
void on_replacement_field(
int id,
const Char*) {
3076 auto arg = get_arg(context,
id);
3077 context.advance_to(visit_format_arg(
3083 const Char* on_format_specs(
int id,
const Char* begin,
const Char* end) {
3084 auto arg = get_arg(context,
id);
3085 if (arg.type() == type::custom_type) {
3086 advance_to(parse_context, begin);
3088 return parse_context.
begin();
3091 if (begin + 1 < end && begin[1] ==
'}' && is_ascii_letter(*begin)) {
3092 specs.type =
static_cast<char>(*begin++);
3099 begin = parse_format_specs(begin, end, handler);
3100 if (begin == end || *begin !=
'}')
3101 on_error(
"missing '}' in format string");
3103 context.advance_to(visit_format_arg(
3113 template <
typename Char,
typename ErrorHandler = error_handler>
3123 ErrorHandler eh = {})
3124 :
base(format_str, eh), num_args_(num_args) {}
3126 FMT_CONSTEXPR
int next_arg_id() {
3127 int id = base::next_arg_id();
3128 if (
id >= num_args_) this->on_error(
"argument not found");
3132 FMT_CONSTEXPR
void check_arg_id(
int id) {
3133 base::check_arg_id(
id);
3134 if (
id >= num_args_) this->on_error(
"argument not found");
3136 using base::check_arg_id;
3139 template <
typename Char,
typename ErrorHandler,
typename... Args>
3144 : context_(format_str, num_args, eh),
3145 parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {}
3147 FMT_CONSTEXPR
void on_text(
const Char*,
const Char*) {}
3149 FMT_CONSTEXPR
int on_arg_id() {
return context_.next_arg_id(); }
3150 FMT_CONSTEXPR
int on_arg_id(
int id) {
return context_.check_arg_id(
id), id; }
3152 on_error(
"compile-time checks don't support named arguments");
3156 FMT_CONSTEXPR
void on_replacement_field(
int,
const Char*) {}
3158 FMT_CONSTEXPR
const Char* on_format_specs(
int id,
const Char* begin,
3160 advance_to(context_, begin);
3161 return id < num_args ? parse_funcs_[id](context_) : begin;
3164 FMT_CONSTEXPR
void on_error(
const char* message) {
3165 context_.on_error(message);
3170 enum { num_args =
sizeof...(Args) };
3176 parse_func parse_funcs_[num_args > 0 ? num_args : 1];
3180 template <
typename Char,
size_t N>
3182 const Char (&s)[N]) {
3186 N - ((std::char_traits<Char>::to_int_type(s[N - 1]) == 0) ? 1 : 0)};
3190 template <
typename Char>
3193 return {s.data(), s.size()};
3196 #define FMT_STRING_IMPL(s, base) \ 3199 struct FMT_COMPILE_STRING : base { \ 3200 using char_type = fmt::remove_cvref_t<decltype(s[0])>; \ 3201 FMT_MAYBE_UNUSED FMT_CONSTEXPR \ 3202 operator fmt::basic_string_view<char_type>() const { \ 3203 return fmt::detail::compile_string_to_view<char_type>(s); \ 3206 return FMT_COMPILE_STRING(); \ 3219 #define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string) 3221 template <
typename... Args,
typename S,
3222 enable_if_t<(is_compile_string<S>::value),
int>>
3223 void check_format_string(S format_str) {
3224 FMT_CONSTEXPR_DECL
auto s = to_string_view(format_str);
3226 remove_cvref_t<Args>...>;
3227 FMT_CONSTEXPR_DECL
bool invalid_format =
3228 (parse_format_string<true>(s, checker(s, {})),
true);
3229 (void)invalid_format;
3232 template <
template <
typename>
class Handler,
typename Context>
3236 case arg_id_kind::none:
3238 case arg_id_kind::index:
3239 value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.index),
3240 ctx.error_handler());
3242 case arg_id_kind::name:
3243 value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.name),
3244 ctx.error_handler());
3254 FMT_API
void report_error(format_func func,
int error_code,
3258 template <
typename OutputIt,
typename Char>
3274 system_error() : std::runtime_error(
""), error_code_(0) {}
3295 template <
typename... Args>
3297 :
std::runtime_error(
"") {
3298 init(error_code, message, make_format_args(args...));
3306 int error_code()
const {
return error_code_; }
3330 FMT_API
void report_system_error(
int error_code,
3338 enum { buffer_size = std::numeric_limits<unsigned long long>::digits10 + 3 };
3339 mutable char buffer_[buffer_size];
3342 template <
typename UInt>
char* format_unsigned(UInt value) {
3343 auto n =
static_cast<detail::uint32_or_64_or_128_t<UInt>
>(value);
3344 return detail::format_decimal(buffer_, n, buffer_size - 1).begin;
3347 template <
typename Int>
char* format_signed(Int value) {
3348 auto abs_value =
static_cast<detail::uint32_or_64_or_128_t<Int>
>(value);
3349 bool negative = value < 0;
3350 if (negative) abs_value = 0 - abs_value;
3351 auto begin = format_unsigned(abs_value);
3352 if (negative) *--begin =
'-';
3357 explicit format_int(
int value) : str_(format_signed(value)) {}
3358 explicit format_int(
long value) : str_(format_signed(value)) {}
3359 explicit format_int(
long long value) : str_(format_signed(value)) {}
3360 explicit format_int(
unsigned value) : str_(format_unsigned(value)) {}
3361 explicit format_int(
unsigned long value) : str_(format_unsigned(value)) {}
3362 explicit format_int(
unsigned long long value)
3363 : str_(format_unsigned(value)) {}
3367 return detail::to_unsigned(buffer_ - str_ + buffer_size - 1);
3374 const char*
data()
const {
return str_; }
3381 buffer_[buffer_size - 1] =
'\0';
3390 std::string
str()
const {
return std::string(str_, size()); }
3395 template <
typename T,
typename Char>
3397 enable_if_t<
detail::type_constant<T, Char>::value !=
3398 detail::type::custom_type>> {
3403 template <
typename ParseContext>
3404 FMT_CONSTEXPR
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
3409 auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
3410 auto eh = ctx.error_handler();
3412 case detail::type::none_type:
3413 FMT_ASSERT(
false,
"invalid argument type");
3415 case detail::type::int_type:
3416 case detail::type::uint_type:
3417 case detail::type::long_long_type:
3418 case detail::type::ulong_long_type:
3419 case detail::type::int128_type:
3420 case detail::type::uint128_type:
3421 case detail::type::bool_type:
3422 handle_int_type_spec(specs_.type,
3425 case detail::type::char_type:
3429 case detail::type::float_type:
3430 if (detail::const_check(FMT_USE_FLOAT))
3431 detail::parse_float_type_spec(specs_, eh);
3433 FMT_ASSERT(
false,
"float support disabled");
3435 case detail::type::double_type:
3436 if (detail::const_check(FMT_USE_DOUBLE))
3437 detail::parse_float_type_spec(specs_, eh);
3439 FMT_ASSERT(
false,
"double support disabled");
3441 case detail::type::long_double_type:
3442 if (detail::const_check(FMT_USE_LONG_DOUBLE))
3443 detail::parse_float_type_spec(specs_, eh);
3445 FMT_ASSERT(
false,
"long double support disabled");
3447 case detail::type::cstring_type:
3448 detail::handle_cstring_type_spec(
3451 case detail::type::string_type:
3452 detail::check_string_type_spec(specs_.type, eh);
3454 case detail::type::pointer_type:
3455 detail::check_pointer_type_spec(specs_.type, eh);
3457 case detail::type::custom_type:
3465 template <
typename FormatContext>
3466 auto format(
const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
3467 detail::handle_dynamic_spec<detail::width_checker>(specs_.width,
3468 specs_.width_ref, ctx);
3469 detail::handle_dynamic_spec<detail::precision_checker>(
3470 specs_.precision, specs_.precision_ref, ctx);
3472 typename FormatContext::char_type>;
3473 return visit_format_arg(af(ctx,
nullptr, &specs_),
3474 detail::make_arg<FormatContext>(val));
3481 #define FMT_FORMAT_AS(Type, Base) \ 3482 template <typename Char> \ 3483 struct formatter<Type, Char> : formatter<Base, Char> { \ 3484 template <typename FormatContext> \ 3485 auto format(Type const& val, FormatContext& ctx) -> decltype(ctx.out()) { \ 3486 return formatter<Base, Char>::format(val, ctx); \ 3490 FMT_FORMAT_AS(
signed char,
int);
3491 FMT_FORMAT_AS(
unsigned char,
unsigned);
3492 FMT_FORMAT_AS(
short,
int);
3493 FMT_FORMAT_AS(
unsigned short,
unsigned);
3494 FMT_FORMAT_AS(
long,
long long);
3495 FMT_FORMAT_AS(
unsigned long,
unsigned long long);
3496 FMT_FORMAT_AS(Char*,
const Char*);
3498 FMT_FORMAT_AS(std::nullptr_t,
const void*);
3501 template <
typename Char>
3503 template <
typename FormatContext>
3504 auto format(
void* val, FormatContext& ctx) -> decltype(ctx.out()) {
3509 template <
typename Char,
size_t N>
3511 template <
typename FormatContext>
3512 auto format(
const Char* val, FormatContext& ctx) -> decltype(ctx.out()) {
3532 void on_align(align_t) {}
3540 template <
typename ParseContext>
3541 auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
3542 format_str_ = ctx.begin();
3545 return parse_format_specs(ctx.begin(), ctx.end(), handler);
3548 template <
typename T,
typename FormatContext>
3549 auto format(
const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
3553 checker.on_align(specs_.align);
3554 switch (specs_.sign) {
3567 if (specs_.alt) checker.on_hash();
3568 if (specs_.precision >= 0) checker.end_precision();
3570 typename FormatContext::char_type>;
3571 visit_format_arg(af(ctx,
nullptr, &specs_),
3572 detail::make_arg<FormatContext>(val));
3577 template <
typename Context>
void handle_specs(Context& ctx) {
3578 detail::handle_dynamic_spec<detail::width_checker>(specs_.width,
3579 specs_.width_ref, ctx);
3580 detail::handle_dynamic_spec<detail::precision_checker>(
3581 specs_.precision, specs_.precision_ref, ctx);
3585 const Char* format_str_;
3588 template <
typename Char,
typename ErrorHandler>
3589 FMT_CONSTEXPR
void advance_to(
3603 template <
typename T>
inline const void* ptr(
const T* p) {
return p; }
3604 template <
typename T>
inline const void* ptr(
const std::unique_ptr<T>& p) {
3607 template <
typename T>
inline const void* ptr(
const std::shared_ptr<T>& p) {
3625 template <
typename ParseContext>
3626 FMT_CONSTEXPR
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
3629 detail::type::string_type);
3630 auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
3631 detail::check_string_type_spec(specs_.type, ctx.error_handler());
3635 template <
typename FormatContext>
3636 auto format(
bytes b, FormatContext& ctx) -> decltype(ctx.out()) {
3637 detail::handle_dynamic_spec<detail::width_checker>(specs_.width,
3638 specs_.width_ref, ctx);
3639 detail::handle_dynamic_spec<detail::precision_checker>(
3640 specs_.precision, specs_.precision_ref, ctx);
3641 return detail::write_bytes(ctx.out(), b.data_, specs_);
3645 template <
typename It,
typename Sentinel,
typename Char>
3652 : begin(b), end(e), sep(s) {}
3655 template <
typename It,
typename Sentinel,
typename Char>
3657 :
formatter<typename std::iterator_traits<It>::value_type, Char> {
3658 template <
typename FormatContext>
3660 -> decltype(ctx.out()) {
3662 auto it = value.begin;
3663 auto out = ctx.out();
3664 if (it != value.end) {
3665 out = base::format(*it++, ctx);
3666 while (it != value.end) {
3667 out = std::copy(value.sep.begin(), value.sep.end(), out);
3668 ctx.advance_to(out);
3669 out = base::format(*it++, ctx);
3680 template <
typename It,
typename Sentinel>
3682 return {begin, end, sep};
3685 template <
typename It,
typename Sentinel>
3687 return {begin, end, sep};
3706 template <
typename Range>
3709 return join(std::begin(range), std::end(range), sep);
3712 template <
typename Range>
3715 return join(std::begin(range), std::end(range), sep);
3729 template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
3730 inline std::string to_string(
const T& value) {
3732 detail::write<char>(std::back_inserter(result), value);
3736 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
3737 inline std::string to_string(T value) {
3740 constexpr
int max_size = detail::digits10<T>() + 2;
3741 char buffer[max_size > 5 ?
static_cast<unsigned>(max_size) : 5];
3743 return std::string(begin, detail::write<char>(begin, value));
3749 template <
typename T>
inline std::wstring to_wstring(
const T& value) {
3750 return format(L
"{}", value);
3753 template <
typename Char,
size_t SIZE>
3755 auto size = buf.
size();
3756 detail::assume(size < std::basic_string<Char>().max_size());
3757 return std::basic_string<Char>(buf.
data(), size);
3760 template <
typename Char>
3761 void detail::vformat_to(
3765 using iterator =
typename buffer_context<Char>::iterator;
3766 auto out = buffer_appender<Char>(buf);
3767 if (format_str.
size() == 2 && equal2(format_str.
data(),
"{}")) {
3768 auto arg = args.get(0);
3769 if (!arg) error_handler().on_error(
"argument not found");
3770 visit_format_arg(default_arg_formatter<iterator, Char>{out, args, loc},
3774 format_handler<iterator, Char, buffer_context<Char>> h(out, format_str, args,
3776 parse_format_string<false>(format_str, h);
3779 #ifndef FMT_HEADER_ONLY 3785 extern template FMT_API std::string grouping_impl<char>(locale_ref loc);
3786 extern template FMT_API std::string grouping_impl<wchar_t>(locale_ref loc);
3787 extern template FMT_API
char thousands_sep_impl<char>(locale_ref loc);
3788 extern template FMT_API
wchar_t thousands_sep_impl<wchar_t>(locale_ref loc);
3789 extern template FMT_API
char decimal_point_impl(locale_ref loc);
3790 extern template FMT_API
wchar_t decimal_point_impl(locale_ref loc);
3791 extern template int format_float<double>(
double value,
int precision,
3792 float_specs specs, buffer<char>& buf);
3793 extern template int format_float<long double>(
long double value,
int precision,
3796 int snprintf_float(
float value,
int precision, float_specs specs,
3797 buffer<char>& buf) =
delete;
3798 extern template int snprintf_float<double>(
double value,
int precision,
3801 extern template int snprintf_float<long double>(
long double value,
3808 template <
typename S,
typename Char =
char_t<S>,
3809 FMT_ENABLE_IF(detail::is_
string<S>::value)>
3810 inline void vformat_to(
3813 return detail::vformat_to(buf, to_string_view(format_str), args);
3816 template <
typename S,
typename... Args,
size_t SIZE = inline_buffer_size,
3817 typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
3818 inline typename buffer_context<Char>::iterator format_to(
3820 const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
3821 detail::vformat_to(buf, to_string_view(format_str), vargs);
3825 template <
typename OutputIt,
typename Char =
char>
3828 template <
typename OutputIt,
typename Char =
char>
3831 template <
typename OutputIt,
typename Char =
typename OutputIt::value_type>
3834 template <
typename OutputIt,
typename Char =
typename OutputIt::value_type>
3835 using format_to_n_args FMT_DEPRECATED_ALIAS =
3838 template <
typename OutputIt,
typename Char,
typename... Args>
3840 make_format_to_n_args(
const Args&... args) {
3841 return format_arg_store<buffer_context<Char>, Args...>(args...);
3844 template <typename Char, enable_if_t<(!std::is_same<Char, char>::value),
int>>
3845 std::basic_string<Char> detail::vformat(
3849 detail::vformat_to(buffer, format_str, args);
3850 return to_string(buffer);
3853 template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)>
3857 detail::vformat_to(buffer, format_str, args);
3858 buffer.push_back(L
'\0');
3859 if (std::fputws(buffer.
data(), f) == -1)
3860 FMT_THROW(
system_error(errno,
"cannot write to file"));
3863 template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)>
3865 vprint(stdout, format_str, args);
3868 #if FMT_USE_USER_DEFINED_LITERALS 3871 # if FMT_USE_UDL_TEMPLATE 3872 template <
typename Char, Char... CHARS>
class udl_formatter {
3874 template <
typename... Args>
3875 std::basic_string<Char> operator()(Args&&... args)
const {
3876 static FMT_CONSTEXPR_DECL Char
s[] = {CHARS...,
'\0'};
3877 return format(FMT_STRING(s), std::forward<Args>(args)...);
3881 template <
typename Char>
struct udl_formatter {
3884 template <
typename... Args>
3885 std::basic_string<Char> operator()(Args&&... args)
const {
3886 return format(str, std::forward<Args>(args)...);
3889 # endif // FMT_USE_UDL_TEMPLATE 3891 template <
typename Char>
struct udl_arg {
3894 template <
typename T> named_arg<Char, T> operator=(T&& value)
const {
3895 return {str, std::forward<T>(value)};
3900 inline namespace literals {
3901 # if FMT_USE_UDL_TEMPLATE 3902 # pragma GCC diagnostic push 3903 # pragma GCC diagnostic ignored "-Wpedantic" 3904 # if FMT_CLANG_VERSION 3905 # pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template" 3907 template <
typename Char, Char... CHARS>
3908 FMT_CONSTEXPR detail::udl_formatter<Char, CHARS...>
operator""_format() {
3911 # pragma GCC diagnostic pop 3923 FMT_CONSTEXPR detail::udl_formatter<char>
operator"" _format(
const char*
s,
3927 FMT_CONSTEXPR detail::udl_formatter<wchar_t>
operator"" _format(
3928 const wchar_t* s,
size_t n) {
3931 # endif // FMT_USE_UDL_TEMPLATE 3943 FMT_CONSTEXPR detail::udl_arg<char>
operator"" _a(
const char* s,
size_t) {
3946 FMT_CONSTEXPR detail::udl_arg<wchar_t>
operator"" _a(
const wchar_t* s,
size_t) {
3950 #endif // FMT_USE_USER_DEFINED_LITERALS 3953 #ifdef FMT_HEADER_ONLY 3954 # define FMT_FUNC inline 3955 # include "format-inl.h" 3960 #endif // FMT_FORMAT_H_
Definition: format.h:1174
Definition: format-inl.h:1095
A dynamically growing memory buffer for trivially copyable/constructible types with the first SIZE el...
Definition: format.h:654
void append(const U *begin, const U *end)
Appends data to the end of the buffer.
Definition: format.h:600
Definition: format.h:3114
void reserve(size_t new_capacity)
Increases the buffer capacity to new_capacity.
Definition: format.h:730
FMT_CONSTEXPR void advance_to(iterator it)
Advances the begin iterator to it.
Definition: core.h:585
Definition: blocking.hpp:208
constexpr const Char * data() const
Returns a pointer to the string data.
Definition: core.h:396
Definition: format.h:2501
Definition: format.h:2414
Definition: format.h:2394
size_t size() const FMT_NOEXCEPT
Returns the size of this buffer.
Definition: core.h:706
Definition: awaitable.hpp:421
An error returned by an operating system or a language runtime, for example a file opening error...
Definition: format.h:3267
system_error(int error_code, string_view message, const Args &... args)
Constructs a :class:fmt::system_error object with a description formatted with fmt::format_system_err...
Definition: format.h:3296
Definition: format.h:1458
Definition: format.h:1142
An implementation of std::basic_string_view for pre-C++17.
Definition: core.h:355
constexpr iterator begin() const FMT_NOEXCEPT
Returns an iterator to the beginning of the format string range being parsed.
Definition: core.h:577
std::size_t write(SyncWriteStream &s, const ConstBufferSequence &buffers, CompletionCondition completion_condition, asio::error_code &ec, typename enable_if< is_const_buffer_sequence< ConstBufferSequence >::value >::type *)
Write a certain amount of data to a stream before returning.
Definition: write.hpp:64
Definition: format.h:1531
ASIO_MUTABLE_BUFFER buffer(const mutable_buffer &b) ASIO_NOEXCEPT
Create a new modifiable buffer from an existing buffer.
Definition: buffer.hpp:909
Definition: format.h:3646
Definition: format.h:1179
FMT_CONSTEXPR int next_arg_id()
Reports an error if using the manual argument indexing; otherwise returns the next argument index and...
Definition: core.h:593
Definition: format.h:2567
Definition: format-inl.h:1078
Definition: format.h:2650
Definition: format.h:2471
Definition: format.h:1209
Definition: format.h:2614
Definition: format.h:1287
Definition: format.h:1735
Definition: format.h:1145
Definition: format.h:1473
Definition: format.h:1441
Definition: format.h:2435
Definition: format.h:2944
Definition: format.h:1130
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:706
Definition: format.h:1584
Definition: format.h:2556
void resize(size_t count)
Resizes the buffer to contain count elements.
Definition: format.h:727
Definition: format.h:2001
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:605
A contiguous memory buffer with an optional growing ability.
Definition: core.h:665
Definition: format.h:1263
Definition: format.h:2733
void grow(size_t size) final FMT_OVERRIDE
Increases the buffer capacity to hold at least capacity elements.
Definition: format.h:741
T * data() FMT_NOEXCEPT
Returns a pointer to the buffer data.
Definition: core.h:712
void set(T *buf_data, size_t buf_capacity) FMT_NOEXCEPT
Sets the buffer data and capacity.
Definition: core.h:684
Definition: format.h:3611
constexpr size_t size() const
Returns the string size.
Definition: core.h:399
basic_memory_buffer & operator=(basic_memory_buffer &&other) FMT_NOEXCEPT
Moves the content of the other basic_memory_buffer object to this one.
Definition: format.h:713
size_t capacity() const FMT_NOEXCEPT
Returns the capacity of this buffer.
Definition: core.h:709
Definition: format.h:2750