46#ifdef FMT_DEPRECATED_INCLUDE_OS
50#ifdef __INTEL_COMPILER
51# define FMT_ICC_VERSION __INTEL_COMPILER
53# define FMT_ICC_VERSION __ICL
55# define FMT_ICC_VERSION 0
59# define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__)
61# define FMT_CUDA_VERSION 0
65# define FMT_HAS_BUILTIN(x) __has_builtin(x)
67# define FMT_HAS_BUILTIN(x) 0
70#if FMT_GCC_VERSION || FMT_CLANG_VERSION
71# define FMT_NOINLINE __attribute__((noinline))
76#if __cplusplus == 201103L || __cplusplus == 201402L
77# if defined(__clang__)
78# define FMT_FALLTHROUGH [[clang::fallthrough]]
79# elif FMT_GCC_VERSION >= 700 && !defined(__PGI)
80# define FMT_FALLTHROUGH [[gnu::fallthrough]]
82# define FMT_FALLTHROUGH
84#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) || \
85 (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
86# define FMT_FALLTHROUGH [[fallthrough]]
88# define FMT_FALLTHROUGH
93# if FMT_MSC_VER || FMT_NVCC
96template <
typename Exception>
inline void do_throw(
const Exception& x) {
99 volatile bool b =
true;
104# define FMT_THROW(x) internal::do_throw(x)
106# define FMT_THROW(x) throw x
109# define FMT_THROW(x) \
111 static_cast<void>(sizeof(x)); \
112 FMT_ASSERT(false, ""); \
119# define FMT_CATCH(x) catch (x)
121# define FMT_TRY if (true)
122# define FMT_CATCH(x) if (false)
125#ifndef FMT_USE_USER_DEFINED_LITERALS
127# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \
128 FMT_MSC_VER >= 1900) && \
129 (!(FMT_ICC_VERSION || FMT_CUDA_VERSION) || FMT_ICC_VERSION >= 1500 || \
130 FMT_CUDA_VERSION >= 700)
131# define FMT_USE_USER_DEFINED_LITERALS 1
133# define FMT_USE_USER_DEFINED_LITERALS 0
137#ifndef FMT_USE_UDL_TEMPLATE
140# if FMT_USE_USER_DEFINED_LITERALS && FMT_ICC_VERSION == 0 && \
141 FMT_CUDA_VERSION == 0 && \
142 ((FMT_GCC_VERSION >= 604 && FMT_GCC_VERSION <= 900 && \
143 __cplusplus >= 201402L) || \
144 FMT_CLANG_VERSION >= 304)
145# define FMT_USE_UDL_TEMPLATE 1
147# define FMT_USE_UDL_TEMPLATE 0
152# define FMT_USE_FLOAT 1
155#ifndef FMT_USE_DOUBLE
156# define FMT_USE_DOUBLE 1
159#ifndef FMT_USE_LONG_DOUBLE
160# define FMT_USE_LONG_DOUBLE 1
165#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)) && !FMT_MSC_VER
166# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
168#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clzll)) && !FMT_MSC_VER
169# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
175#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED)
182# pragma intrinsic(_BitScanReverse)
184inline uint32_t clz(uint32_t x) {
186 _BitScanReverse(&r, x);
188 FMT_ASSERT(x != 0,
"");
192# pragma warning(suppress : 6102)
195# define FMT_BUILTIN_CLZ(n) internal::clz(n)
197# if defined(_WIN64) && !defined(__clang__)
198# pragma intrinsic(_BitScanReverse64)
201inline uint32_t clzll(uint64_t x) {
204 _BitScanReverse64(&r, x);
207 if (_BitScanReverse(&r,
static_cast<uint32_t
>(x >> 32)))
return 63 - (r + 32);
210 _BitScanReverse(&r,
static_cast<uint32_t
>(x));
213 FMT_ASSERT(x != 0,
"");
217# pragma warning(suppress : 6102)
220# define FMT_BUILTIN_CLZLL(n) internal::clzll(n)
226#ifndef FMT_NUMERIC_ALIGN
227# define FMT_NUMERIC_ALIGN 1
231#ifndef FMT_DEPRECATED_PERCENT
232# define FMT_DEPRECATED_PERCENT 0
241template <
typename Dest,
typename Source>
242inline Dest bit_cast(
const Source& source) {
243 static_assert(
sizeof(Dest) ==
sizeof(Source),
"size mismatch");
245 std::memcpy(&dest, &source,
sizeof(dest));
249inline bool is_big_endian() {
252 char data[
sizeof(u)];
254 return bit_cast<bytes>(u).data[0] == 0;
258struct fallback_uintptr {
259 unsigned char value[
sizeof(
void*)];
261 fallback_uintptr() =
default;
262 explicit fallback_uintptr(
const void* p) {
263 *
this = bit_cast<fallback_uintptr>(p);
264 if (is_big_endian()) {
265 for (
size_t i = 0, j =
sizeof(
void*) - 1; i < j; ++i, --j)
266 std::swap(value[i], value[j]);
271using uintptr_t = ::uintptr_t;
272inline uintptr_t to_uintptr(
const void* p) {
return bit_cast<uintptr_t>(p); }
274using uintptr_t = fallback_uintptr;
275inline fallback_uintptr to_uintptr(
const void* p) {
276 return fallback_uintptr(p);
282template <
typename T>
constexpr T max_value() {
283 return (std::numeric_limits<T>::max)();
285template <
typename T>
constexpr int num_bits() {
286 return std::numeric_limits<T>::digits;
288template <>
constexpr int num_bits<fallback_uintptr>() {
289 return static_cast<int>(
sizeof(
void*) *
290 std::numeric_limits<unsigned char>::digits);
295using iterator_t =
decltype(std::begin(std::declval<T&>()));
300template <
typename It,
typename Enable =
void>
301struct iterator_category : std::false_type {};
303template <
typename T>
struct iterator_category<T*> {
304 using type = std::random_access_iterator_tag;
307template <
typename It>
308struct iterator_category<It, void_t<typename It::iterator_category>> {
309 using type =
typename It::iterator_category;
313template <
typename It>
class is_output_iterator {
319 template <
typename U>
320 static decltype(*(std::declval<U>())) test(std::input_iterator_tag);
321 template <
typename U>
static char& test(std::output_iterator_tag);
322 template <
typename U>
static const char& test(...);
324 using type =
decltype(test<It>(
typename iterator_category<It>::type{}));
327 enum { value = !std::is_const<remove_reference_t<type>>::value };
331template <
typename Char>
inline Char* get_data(std::basic_string<Char>& s) {
334template <
typename Container>
335inline typename Container::value_type* get_data(Container& c) {
339#if defined(_SECURE_SCL) && _SECURE_SCL
341template <
typename T>
using checked_ptr = stdext::checked_array_iterator<T*>;
342template <
typename T> checked_ptr<T> make_checked(T* p, std::size_t size) {
346template <
typename T>
using checked_ptr = T*;
347template <
typename T>
inline T* make_checked(T* p, std::size_t) {
return p; }
350template <
typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
351inline checked_ptr<typename Container::value_type> reserve(
352 std::back_insert_iterator<Container>& it, std::size_t n) {
353 Container& c = get_container(it);
354 std::size_t size = c.size();
356 return make_checked(get_data(c) + size, n);
359template <
typename Iterator>
360inline Iterator& reserve(Iterator& it, std::size_t) {
366class counting_iterator {
371 using iterator_category = std::output_iterator_tag;
372 using difference_type = std::ptrdiff_t;
373 using pointer = void;
374 using reference = void;
375 using _Unchecked_type = counting_iterator;
378 template <
typename T>
void operator=(
const T&) {}
381 counting_iterator() : count_(0) {}
383 std::size_t count()
const {
return count_; }
385 counting_iterator& operator++() {
390 counting_iterator operator++(
int) {
396 value_type operator*()
const {
return {}; }
399template <
typename OutputIt>
class truncating_iterator_base {
405 truncating_iterator_base(OutputIt out, std::size_t limit)
406 : out_(out), limit_(limit), count_(0) {}
409 using iterator_category = std::output_iterator_tag;
410 using value_type =
typename std::iterator_traits<OutputIt>::value_type;
411 using difference_type = void;
412 using pointer = void;
413 using reference = void;
414 using _Unchecked_type =
415 truncating_iterator_base;
417 OutputIt base()
const {
return out_; }
418 std::size_t count()
const {
return count_; }
423template <
typename OutputIt,
424 typename Enable =
typename std::is_void<
425 typename std::iterator_traits<OutputIt>::value_type>::type>
426class truncating_iterator;
428template <
typename OutputIt>
429class truncating_iterator<OutputIt, std::false_type>
430 :
public truncating_iterator_base<OutputIt> {
431 mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
434 using value_type =
typename truncating_iterator_base<OutputIt>::value_type;
436 truncating_iterator(OutputIt out, std::size_t limit)
437 : truncating_iterator_base<OutputIt>(out, limit) {}
439 truncating_iterator& operator++() {
440 if (this->count_++ < this->limit_) ++this->out_;
444 truncating_iterator operator++(
int) {
450 value_type& operator*()
const {
451 return this->count_ < this->limit_ ? *this->out_ : blackhole_;
455template <
typename OutputIt>
456class truncating_iterator<OutputIt, std::true_type>
457 :
public truncating_iterator_base<OutputIt> {
459 truncating_iterator(OutputIt out, std::size_t limit)
460 : truncating_iterator_base<OutputIt>(out, limit) {}
462 template <
typename T> truncating_iterator& operator=(T val) {
463 if (this->count_++ < this->limit_) *this->out_++ = val;
467 truncating_iterator& operator++() {
return *
this; }
468 truncating_iterator& operator++(
int) {
return *
this; }
469 truncating_iterator& operator*() {
return *
this; }
473template <
typename OutputIt,
typename T =
typename OutputIt::value_type>
479 using value_type = T;
480 using iterator = OutputIt;
483 explicit output_range(OutputIt it) : it_(it) {}
484 OutputIt begin()
const {
return it_; }
485 sentinel end()
const {
return {}; }
488template <
typename Char>
495 const char* data = s.
data();
496 size_t num_code_points = 0;
497 for (
size_t i = 0, size = s.
size(); i != size; ++i) {
498 if ((data[i] & 0xc0) != 0x80) ++num_code_points;
500 return num_code_points;
505 reinterpret_cast<const char*
>(s.
data()), s.
size()));
508template <
typename Char>
510 size_t size = s.
size();
511 return n < size ? n : size;
516 const char8_type* data = s.
data();
517 size_t num_code_points = 0;
518 for (
size_t i = 0, size = s.
size(); i != size; ++i) {
519 if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) {
526inline char8_type to_char8_t(
char c) {
return static_cast<char8_type
>(c); }
528template <
typename InputIt,
typename OutChar>
529using needs_conversion = bool_constant<
530 std::is_same<typename std::iterator_traits<InputIt>::value_type,
532 std::is_same<OutChar, char8_type>::value>;
534template <
typename OutChar,
typename InputIt,
typename OutputIt,
535 FMT_ENABLE_IF(!needs_conversion<InputIt, OutChar>::value)>
536OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) {
537 return std::copy(begin, end, it);
540template <
typename OutChar,
typename InputIt,
typename OutputIt,
541 FMT_ENABLE_IF(needs_conversion<InputIt, OutChar>::value)>
542OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) {
543 return std::transform(begin, end, it, to_char8_t);
547# define FMT_USE_GRISU 1
550template <
typename T>
constexpr bool use_grisu() {
551 return FMT_USE_GRISU && std::numeric_limits<double>::is_iec559 &&
552 sizeof(T) <=
sizeof(
double);
558 std::size_t new_size = size_ + to_unsigned(end - begin);
560 std::uninitialized_copy(begin, end, make_checked(ptr_, capacity_) + size_);
567class buffer_range :
public internal::output_range<
568 std::back_insert_iterator<internal::buffer<T>>, T> {
570 using iterator = std::back_insert_iterator<internal::buffer<T>>;
571 using internal::output_range<iterator, T>::output_range;
573 : internal::output_range<iterator, T>(std::back_inserter(buf)) {}
576class FMT_DEPRECATED u8string_view
579 u8string_view(
const char* s)
581 reinterpret_cast<const internal::char8_type*>(s)) {}
582 u8string_view(
const char* s,
size_t count) FMT_NOEXCEPT
584 reinterpret_cast<const internal::char8_type*
>(s), count) {}
587#if FMT_USE_USER_DEFINED_LITERALS
588inline namespace literals {
590 const char* s, std::size_t n) {
591 return {
reinterpret_cast<const internal::char8_type*
>(s), n};
598enum { inline_buffer_size = 500 };
629template <
typename T, std::size_t SIZE = inline_buffer_size,
630 typename Allocator = std::allocator<T>>
638 if (data != store_) Allocator::deallocate(
data, this->
capacity());
645 using value_type = T;
646 using const_reference =
const T&;
650 this->
set(store_, SIZE);
657 Allocator &this_alloc = *
this, &other_alloc = other;
658 this_alloc = std::move(other_alloc);
661 if (
data == other.store_) {
663 std::uninitialized_copy(other.store_, other.store_ +
size,
664 internal::make_checked(store_,
capacity));
669 other.
set(other.store_, 0);
689 FMT_ASSERT(
this != &other,
"");
696 Allocator get_allocator()
const {
return *
this; }
699template <
typename T, std::
size_t SIZE,
typename Allocator>
701#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
702 if (size > 1000)
throw std::runtime_error(
"fuzz mode - won't grow that much");
704 std::size_t old_capacity = this->capacity();
705 std::size_t new_capacity = old_capacity + old_capacity / 2;
706 if (size > new_capacity) new_capacity = size;
707 T* old_data = this->data();
708 T* new_data = std::allocator_traits<Allocator>::allocate(*
this, new_capacity);
710 std::uninitialized_copy(old_data, old_data + this->size(),
711 internal::make_checked(new_data, new_capacity));
712 this->set(new_data, new_capacity);
716 if (old_data != store_) Allocator::deallocate(old_data, old_capacity);
726 explicit format_error(
const char* message) : std::runtime_error(message) {}
728 : std::runtime_error(message) {}
740template <
typename T, FMT_ENABLE_IF(std::numeric_limits<T>::is_
signed)>
741FMT_CONSTEXPR
bool is_negative(T value) {
744template <
typename T, FMT_ENABLE_IF(!std::numeric_limits<T>::is_
signed)>
745FMT_CONSTEXPR
bool is_negative(T) {
749template <
typename T, FMT_ENABLE_IF(std::is_
floating_po
int<T>::value)>
750FMT_CONSTEXPR
bool is_supported_floating_point(T) {
751 return (std::is_same<T, float>::value && FMT_USE_FLOAT) ||
752 (std::is_same<T, double>::value && FMT_USE_DOUBLE) ||
753 (std::is_same<T, long double>::value && FMT_USE_LONG_DOUBLE);
759using uint32_or_64_or_128_t = conditional_t<
760 std::numeric_limits<T>::digits <= 32, uint32_t,
761 conditional_t<std::numeric_limits<T>::digits <= 64, uint64_t, uint128_t>>;
764template <
typename T =
void>
struct FMT_EXTERN_TEMPLATE_API basic_data {
765 static const uint64_t powers_of_10_64[];
766 static const uint32_t zero_or_powers_of_10_32[];
767 static const uint64_t zero_or_powers_of_10_64[];
768 static const uint64_t pow10_significands[];
769 static const int16_t pow10_exponents[];
770 static const char digits[];
771 static const char hex_digits[];
772 static const char foreground_color[];
773 static const char background_color[];
774 static const char reset_color[5];
775 static const wchar_t wreset_color[5];
776 static const char signs[];
779FMT_EXTERN
template struct basic_data<void>;
782struct data : basic_data<> {};
784#ifdef FMT_BUILTIN_CLZLL
787inline int count_digits(uint64_t n) {
790 int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12;
791 return t - (n < data::zero_or_powers_of_10_64[t]) + 1;
795inline int count_digits(uint64_t n) {
801 if (n < 10)
return count;
802 if (n < 100)
return count + 1;
803 if (n < 1000)
return count + 2;
804 if (n < 10000)
return count + 3;
812inline int count_digits(uint128_t n) {
818 if (n < 10)
return count;
819 if (n < 100)
return count + 1;
820 if (n < 1000)
return count + 2;
821 if (n < 10000)
return count + 3;
829template <
unsigned BITS,
typename UInt>
inline int count_digits(UInt n) {
833 }
while ((n >>= BITS) != 0);
837template <>
int count_digits<4>(internal::fallback_uintptr n);
839#if FMT_GCC_VERSION || FMT_CLANG_VERSION
840# define FMT_ALWAYS_INLINE inline __attribute__((always_inline))
842# define FMT_ALWAYS_INLINE
845#ifdef FMT_BUILTIN_CLZ
847inline int count_digits(uint32_t n) {
848 int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12;
849 return t - (n < data::zero_or_powers_of_10_32[t]) + 1;
853template <
typename Char> FMT_API std::string grouping_impl(locale_ref loc);
854template <
typename Char>
inline std::string grouping(locale_ref loc) {
855 return grouping_impl<char>(loc);
857template <>
inline std::string grouping<wchar_t>(locale_ref loc) {
858 return grouping_impl<wchar_t>(loc);
861template <
typename Char> FMT_API Char thousands_sep_impl(locale_ref loc);
862template <
typename Char>
inline Char thousands_sep(locale_ref loc) {
863 return Char(thousands_sep_impl<char>(loc));
865template <>
inline wchar_t thousands_sep(locale_ref loc) {
866 return thousands_sep_impl<wchar_t>(loc);
869template <
typename Char> FMT_API Char decimal_point_impl(locale_ref loc);
870template <
typename Char>
inline Char decimal_point(locale_ref loc) {
871 return Char(decimal_point_impl<char>(loc));
873template <>
inline wchar_t decimal_point(locale_ref loc) {
874 return decimal_point_impl<wchar_t>(loc);
880template <
typename UInt,
typename Char,
typename F>
881inline Char* format_decimal(Char* buffer, UInt value,
int num_digits,
882 F add_thousands_sep) {
883 FMT_ASSERT(num_digits >= 0,
"invalid digit count");
884 buffer += num_digits;
886 while (value >= 100) {
890 auto index =
static_cast<unsigned>((value % 100) * 2);
892 *--buffer =
static_cast<Char
>(data::digits[index + 1]);
893 add_thousands_sep(buffer);
894 *--buffer =
static_cast<Char
>(data::digits[index]);
895 add_thousands_sep(buffer);
898 *--buffer =
static_cast<Char
>(
'0' + value);
901 auto index =
static_cast<unsigned>(value * 2);
902 *--buffer =
static_cast<Char
>(data::digits[index + 1]);
903 add_thousands_sep(buffer);
904 *--buffer =
static_cast<Char
>(data::digits[index]);
908template <
typename Int>
constexpr int digits10() FMT_NOEXCEPT {
909 return std::numeric_limits<Int>::digits10;
911template <>
constexpr int digits10<int128_t>() FMT_NOEXCEPT {
return 38; }
912template <>
constexpr int digits10<uint128_t>() FMT_NOEXCEPT {
return 38; }
914template <
typename Char,
typename UInt,
typename Iterator,
typename F>
915inline Iterator format_decimal(Iterator out, UInt value,
int num_digits,
916 F add_thousands_sep) {
917 FMT_ASSERT(num_digits >= 0,
"invalid digit count");
919 enum { max_size = digits10<UInt>() + 1 };
920 Char buffer[2 * max_size];
921 auto end = format_decimal(buffer, value, num_digits, add_thousands_sep);
922 return internal::copy_str<Char>(buffer, end, out);
925template <
typename Char,
typename It,
typename UInt>
926inline It format_decimal(It out, UInt value,
int num_digits) {
927 return format_decimal<Char>(out, value, num_digits, [](Char*) {});
930template <
unsigned BASE_BITS,
typename Char,
typename UInt>
931inline Char* format_uint(Char* buffer, UInt value,
int num_digits,
932 bool upper =
false) {
933 buffer += num_digits;
936 const char* digits = upper ?
"0123456789ABCDEF" : data::hex_digits;
937 unsigned digit = (value & ((1 << BASE_BITS) - 1));
938 *--buffer =
static_cast<Char
>(BASE_BITS < 4 ? static_cast<char>(
'0' + digit)
940 }
while ((value >>= BASE_BITS) != 0);
944template <
unsigned BASE_BITS,
typename Char>
945Char* format_uint(Char* buffer, internal::fallback_uintptr n,
int num_digits,
947 auto char_digits = std::numeric_limits<unsigned char>::digits / 4;
948 int start = (num_digits + char_digits - 1) / char_digits - 1;
949 if (
int start_digits = num_digits % char_digits) {
950 unsigned value = n.value[start--];
951 buffer = format_uint<BASE_BITS>(buffer, value, start_digits);
953 for (; start >= 0; --start) {
954 unsigned value = n.value[start];
955 buffer += char_digits;
957 for (
int i = 0; i < char_digits; ++i) {
958 unsigned digit = (value & ((1 << BASE_BITS) - 1));
959 *--p =
static_cast<Char
>(data::hex_digits[digit]);
966template <
unsigned BASE_BITS,
typename Char,
typename It,
typename UInt>
967inline It format_uint(It out, UInt value,
int num_digits,
bool upper =
false) {
969 char buffer[num_bits<UInt>() / BASE_BITS + 1];
970 format_uint<BASE_BITS>(buffer, value, num_digits, upper);
971 return internal::copy_str<Char>(buffer, buffer + num_digits, out);
981 operator wstring_view()
const {
return {&buffer_[0], size()}; }
982 size_t size()
const {
return buffer_.
size() - 1; }
983 const wchar_t* c_str()
const {
return &buffer_[0]; }
984 std::wstring str()
const {
return {&buffer_[0], size()}; }
987template <
typename T =
void>
struct null {};
990template <
typename Char>
struct fill_t {
992 enum { max_size = 4 };
993 Char data_[max_size];
998 auto size = s.
size();
999 if (size > max_size) {
1003 for (
size_t i = 0; i < size; ++i) data_[i] = s[i];
1004 size_ =
static_cast<unsigned char>(size);
1007 size_t size()
const {
return size_; }
1008 const Char* data()
const {
return data_; }
1010 FMT_CONSTEXPR Char& operator[](
size_t index) {
return data_[index]; }
1011 FMT_CONSTEXPR
const Char& operator[](
size_t index)
const {
1012 return data_[index];
1015 static FMT_CONSTEXPR fill_t<Char> make() {
1016 auto fill = fill_t<Char>();
1017 fill[0] = Char(
' ');
1027enum type { none, left, right, center, numeric };
1029using align_t = align::type;
1032enum type { none, minus, plus, space };
1034using sign_t = sign::type;
1037template <
typename Char>
struct basic_format_specs {
1044 internal::fill_t<Char> fill;
1046 constexpr basic_format_specs()
1053 fill(internal::fill_t<Char>::make()) {}
1056using format_specs = basic_format_specs<char>;
1061enum class float_format :
unsigned char {
1070 float_format format : 8;
1081template <
typename Char,
typename It> It write_exponent(
int exp, It it) {
1082 FMT_ASSERT(-10000 < exp && exp < 10000,
"exponent out of range");
1084 *it++ =
static_cast<Char
>(
'-');
1087 *it++ =
static_cast<Char
>(
'+');
1090 const char* top = data::digits + (exp / 100) * 2;
1091 if (exp >= 1000) *it++ =
static_cast<Char
>(top[0]);
1092 *it++ =
static_cast<Char
>(top[1]);
1095 const char* d = data::digits + exp * 2;
1096 *it++ =
static_cast<Char
>(d[0]);
1097 *it++ =
static_cast<Char
>(d[1]);
1101template <
typename Char>
class float_writer {
1104 const char* digits_;
1109 Char decimal_point_;
1111 template <
typename It> It prettify(It it)
const {
1113 int full_exp = num_digits_ + exp_;
1114 if (specs_.format == float_format::exp) {
1116 *it++ =
static_cast<Char
>(*digits_);
1117 int num_zeros = specs_.precision - num_digits_;
1118 if (num_digits_ > 1 || specs_.showpoint) *it++ = decimal_point_;
1119 it = copy_str<Char>(digits_ + 1, digits_ + num_digits_, it);
1120 if (num_zeros > 0 && specs_.showpoint)
1121 it = std::fill_n(it, num_zeros,
static_cast<Char
>(
'0'));
1122 *it++ =
static_cast<Char
>(specs_.upper ?
'E' :
'e');
1123 return write_exponent<Char>(full_exp - 1, it);
1125 if (num_digits_ <= full_exp) {
1127 it = copy_str<Char>(digits_, digits_ + num_digits_, it);
1128 it = std::fill_n(it, full_exp - num_digits_,
static_cast<Char
>(
'0'));
1129 if (specs_.showpoint || specs_.precision < 0) {
1130 *it++ = decimal_point_;
1131 int num_zeros = specs_.precision - full_exp;
1132 if (num_zeros <= 0) {
1133 if (specs_.format != float_format::fixed)
1134 *it++ =
static_cast<Char
>(
'0');
1137#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1138 if (num_zeros > 1000)
1139 throw std::runtime_error(
"fuzz mode - avoiding excessive cpu use");
1141 it = std::fill_n(it, num_zeros,
static_cast<Char
>(
'0'));
1143 }
else if (full_exp > 0) {
1145 it = copy_str<Char>(digits_, digits_ + full_exp, it);
1146 if (!specs_.showpoint) {
1148 int num_digits = num_digits_;
1149 while (num_digits > full_exp && digits_[num_digits - 1] ==
'0')
1151 if (num_digits != full_exp) *it++ = decimal_point_;
1152 return copy_str<Char>(digits_ + full_exp, digits_ + num_digits, it);
1154 *it++ = decimal_point_;
1155 it = copy_str<Char>(digits_ + full_exp, digits_ + num_digits_, it);
1156 if (specs_.precision > num_digits_) {
1158 int num_zeros = specs_.precision - num_digits_;
1159 it = std::fill_n(it, num_zeros,
static_cast<Char
>(
'0'));
1163 *it++ =
static_cast<Char
>(
'0');
1164 int num_zeros = -full_exp;
1165 int num_digits = num_digits_;
1166 if (num_digits == 0 && specs_.precision >= 0 &&
1167 specs_.precision < num_zeros) {
1168 num_zeros = specs_.precision;
1171 if (!specs_.showpoint)
1172 while (num_digits > 0 && digits_[num_digits - 1] ==
'0') --num_digits;
1173 if (num_zeros != 0 || num_digits != 0 || specs_.showpoint) {
1174 *it++ = decimal_point_;
1175 it = std::fill_n(it, num_zeros,
static_cast<Char
>(
'0'));
1176 it = copy_str<Char>(digits_, digits_ + num_digits, it);
1183 float_writer(
const char* digits,
int num_digits,
int exp, float_specs specs,
1186 num_digits_(num_digits),
1189 decimal_point_(decimal_point) {
1190 int full_exp = num_digits + exp - 1;
1191 int precision = specs.precision > 0 ? specs.precision : 16;
1192 if (specs_.format == float_format::general &&
1193 !(full_exp >= -4 && full_exp < precision)) {
1194 specs_.format = float_format::exp;
1196 size_ = prettify(counting_iterator()).count();
1197 size_ += specs.sign ? 1 : 0;
1200 size_t size()
const {
return size_; }
1201 size_t width()
const {
return size(); }
1203 template <
typename It>
void operator()(It&& it) {
1204 if (specs_.sign) *it++ =
static_cast<Char
>(data::signs[specs_.sign]);
1209template <
typename T>
1210int format_float(T value,
int precision, float_specs specs, buffer<char>& buf);
1213template <
typename T>
1214int snprintf_float(T value,
int precision, float_specs specs,
1217template <
typename T> T promote_float(T value) {
return value; }
1218inline double promote_float(
float value) {
return static_cast<double>(value); }
1220template <
typename Handler>
1221FMT_CONSTEXPR
void handle_int_type_spec(
char spec, Handler&& handler) {
1247template <
typename ErrorHandler = error_handler,
typename Char>
1248FMT_CONSTEXPR float_specs parse_float_type_spec(
1249 const basic_format_specs<Char>& specs, ErrorHandler&& eh = {}) {
1250 auto result = float_specs();
1251 result.showpoint = specs.alt;
1252 switch (specs.type) {
1254 result.format = float_format::general;
1255 result.showpoint |= specs.precision > 0;
1258 result.upper =
true;
1261 result.format = float_format::general;
1264 result.upper =
true;
1267 result.format = float_format::exp;
1268 result.showpoint |= specs.precision != 0;
1271 result.upper =
true;
1274 result.format = float_format::fixed;
1275 result.showpoint |= specs.precision != 0;
1277#if FMT_DEPRECATED_PERCENT
1279 result.format = float_format::fixed;
1280 result.percent =
true;
1284 result.upper =
true;
1287 result.format = float_format::hex;
1290 result.locale =
true;
1293 eh.on_error(
"invalid type specifier");
1299template <
typename Char,
typename Handler>
1300FMT_CONSTEXPR
void handle_char_specs(
const basic_format_specs<Char>* specs,
1301 Handler&& handler) {
1302 if (!specs)
return handler.on_char();
1303 if (specs->type && specs->type !=
'c')
return handler.on_int();
1304 if (specs->align == align::numeric || specs->sign != sign::none || specs->alt)
1305 handler.on_error(
"invalid format specifier for char");
1309template <
typename Char,
typename Handler>
1310FMT_CONSTEXPR
void handle_cstring_type_spec(Char spec, Handler&& handler) {
1311 if (spec == 0 || spec ==
's')
1312 handler.on_string();
1313 else if (spec ==
'p')
1314 handler.on_pointer();
1316 handler.on_error(
"invalid type specifier");
1319template <
typename Char,
typename ErrorHandler>
1320FMT_CONSTEXPR
void check_string_type_spec(Char spec, ErrorHandler&& eh) {
1321 if (spec != 0 && spec !=
's') eh.on_error(
"invalid type specifier");
1324template <
typename Char,
typename ErrorHandler>
1325FMT_CONSTEXPR
void check_pointer_type_spec(Char spec, ErrorHandler&& eh) {
1326 if (spec != 0 && spec !=
'p') eh.on_error(
"invalid type specifier");
1329template <
typename ErrorHandler>
class int_type_checker :
private ErrorHandler {
1331 FMT_CONSTEXPR
explicit int_type_checker(ErrorHandler eh) : ErrorHandler(eh) {}
1333 FMT_CONSTEXPR
void on_dec() {}
1334 FMT_CONSTEXPR
void on_hex() {}
1335 FMT_CONSTEXPR
void on_bin() {}
1336 FMT_CONSTEXPR
void on_oct() {}
1337 FMT_CONSTEXPR
void on_num() {}
1339 FMT_CONSTEXPR
void on_error() {
1340 ErrorHandler::on_error(
"invalid type specifier");
1344template <
typename ErrorHandler>
1345class char_specs_checker :
public ErrorHandler {
1350 FMT_CONSTEXPR char_specs_checker(
char type, ErrorHandler eh)
1351 : ErrorHandler(eh), type_(type) {}
1353 FMT_CONSTEXPR
void on_int() {
1354 handle_int_type_spec(type_, int_type_checker<ErrorHandler>(*
this));
1356 FMT_CONSTEXPR
void on_char() {}
1359template <
typename ErrorHandler>
1360class cstring_type_checker :
public ErrorHandler {
1362 FMT_CONSTEXPR
explicit cstring_type_checker(ErrorHandler eh)
1363 : ErrorHandler(eh) {}
1365 FMT_CONSTEXPR
void on_string() {}
1366 FMT_CONSTEXPR
void on_pointer() {}
1369template <
typename Context>
1372 map_ =
new entry[internal::to_unsigned(args.max_size())];
1373 if (args.is_packed()) {
1374 for (
int i = 0;; ++i) {
1375 internal::type arg_type = args.type(i);
1376 if (arg_type == internal::type::none_type)
return;
1377 if (arg_type == internal::type::named_arg_type)
1378 push_back(args.values_[i]);
1381 for (
int i = 0, n = args.max_size(); i < n; ++i) {
1382 auto type = args.args_[i].type_;
1383 if (type == internal::type::named_arg_type) push_back(args.args_[i].value_);
1387template <
typename Char>
struct nonfinite_writer {
1390 static constexpr size_t str_size = 3;
1392 size_t size()
const {
return str_size + (sign ? 1 : 0); }
1393 size_t width()
const {
return size(); }
1395 template <
typename It>
void operator()(It&& it)
const {
1396 if (sign) *it++ =
static_cast<Char
>(data::signs[sign]);
1397 it = copy_str<Char>(str, str + str_size, it);
1401template <
typename OutputIt,
typename Char>
1402FMT_NOINLINE OutputIt fill(OutputIt it,
size_t n,
const fill_t<Char>& fill) {
1403 auto fill_size = fill.size();
1404 if (fill_size == 1)
return std::fill_n(it, n, fill[0]);
1405 for (
size_t i = 0; i < n; ++i) it = std::copy_n(fill.data(), fill_size, it);
1411template <
typename Range>
class basic_writer {
1413 using char_type =
typename Range::value_type;
1414 using iterator =
typename Range::iterator;
1415 using format_specs = basic_format_specs<char_type>;
1423 auto reserve(std::size_t n) ->
decltype(internal::reserve(out_, n)) {
1424 return internal::reserve(out_, n);
1427 template <
typename F>
struct padded_int_writer {
1431 std::size_t padding;
1434 size_t size()
const {
return size_; }
1435 size_t width()
const {
return size_; }
1437 template <
typename It>
void operator()(It&& it)
const {
1438 if (prefix.
size() != 0)
1439 it = copy_str<char_type>(prefix.begin(), prefix.end(), it);
1440 it = std::fill_n(it, padding, fill);
1448 template <
typename F>
1449 void write_int(
int num_digits,
string_view prefix, format_specs specs, F f) {
1450 std::size_t size = prefix.
size() + to_unsigned(num_digits);
1451 char_type fill = specs.fill[0];
1452 std::size_t padding = 0;
1453 if (specs.align == align::numeric) {
1454 auto unsiged_width = to_unsigned(specs.width);
1455 if (unsiged_width > size) {
1456 padding = unsiged_width - size;
1457 size = unsiged_width;
1459 }
else if (specs.precision > num_digits) {
1460 size = prefix.
size() + to_unsigned(specs.precision);
1461 padding = to_unsigned(specs.precision - num_digits);
1462 fill =
static_cast<char_type
>(
'0');
1464 if (specs.align == align::none) specs.align = align::right;
1465 write_padded(specs, padded_int_writer<F>{size, prefix, fill, padding, f});
1469 template <
typename Int>
void write_decimal(Int value) {
1470 auto abs_value =
static_cast<uint32_or_64_or_128_t<Int>
>(value);
1471 bool negative = is_negative(value);
1473 if (negative) abs_value = ~abs_value + 1;
1474 int num_digits = count_digits(abs_value);
1475 auto&& it = reserve((negative ? 1 : 0) +
static_cast<size_t>(num_digits));
1476 if (negative) *it++ =
static_cast<char_type
>(
'-');
1477 it = format_decimal<char_type>(it, abs_value, num_digits);
1481 template <
typename Int,
typename Specs>
struct int_writer {
1482 using unsigned_type = uint32_or_64_or_128_t<Int>;
1484 basic_writer<Range>& writer;
1486 unsigned_type abs_value;
1488 unsigned prefix_size;
1492 int_writer(basic_writer<Range>& w, Int value,
const Specs& s)
1495 abs_value(static_cast<unsigned_type>(value)),
1497 if (is_negative(value)) {
1500 abs_value = 0 - abs_value;
1501 }
else if (specs.sign != sign::none && specs.sign != sign::minus) {
1502 prefix[0] = specs.sign == sign::plus ?
'+' :
' ';
1508 unsigned_type abs_value;
1511 template <
typename It>
void operator()(It&& it)
const {
1512 it = internal::format_decimal<char_type>(it, abs_value, num_digits);
1517 int num_digits = count_digits(abs_value);
1518 writer.write_int(num_digits, get_prefix(), specs,
1519 dec_writer{abs_value, num_digits});
1526 template <
typename It>
void operator()(It&& it)
const {
1527 it = format_uint<4, char_type>(it, self.abs_value, num_digits,
1528 self.specs.type !=
'x');
1534 prefix[prefix_size++] =
'0';
1535 prefix[prefix_size++] = specs.type;
1537 int num_digits = count_digits<4>(abs_value);
1538 writer.write_int(num_digits, get_prefix(), specs,
1539 hex_writer{*
this, num_digits});
1542 template <
int BITS>
struct bin_writer {
1543 unsigned_type abs_value;
1546 template <
typename It>
void operator()(It&& it)
const {
1547 it = format_uint<BITS, char_type>(it, abs_value, num_digits);
1553 prefix[prefix_size++] =
'0';
1554 prefix[prefix_size++] =
static_cast<char>(specs.type);
1556 int num_digits = count_digits<1>(abs_value);
1557 writer.write_int(num_digits, get_prefix(), specs,
1558 bin_writer<1>{abs_value, num_digits});
1562 int num_digits = count_digits<3>(abs_value);
1563 if (specs.alt && specs.precision <= num_digits && abs_value != 0) {
1566 prefix[prefix_size++] =
'0';
1568 writer.write_int(num_digits, get_prefix(), specs,
1569 bin_writer<3>{abs_value, num_digits});
1572 enum { sep_size = 1 };
1575 unsigned_type abs_value;
1577 const std::string& groups;
1580 template <
typename It>
void operator()(It&& it)
const {
1584 int digit_index = 0;
1585 std::string::const_iterator group = groups.cbegin();
1586 it = format_decimal<char_type>(
1587 it, abs_value, size,
1588 [
this, s, &group, &digit_index](char_type*& buffer) {
1589 if (*group <= 0 || ++digit_index % *group != 0 ||
1590 *group == max_value<char>())
1592 if (group + 1 != groups.cend()) {
1597 std::uninitialized_copy(s.data(), s.data() + s.size(),
1598 make_checked(buffer, s.size()));
1604 std::string groups = grouping<char_type>(writer.locale_);
1605 if (groups.empty())
return on_dec();
1606 auto sep = thousands_sep<char_type>(writer.locale_);
1607 if (!sep)
return on_dec();
1608 int num_digits = count_digits(abs_value);
1609 int size = num_digits;
1610 std::string::const_iterator group = groups.cbegin();
1611 while (group != groups.cend() && num_digits > *group && *group > 0 &&
1612 *group != max_value<char>()) {
1614 num_digits -= *group;
1617 if (group == groups.cend())
1618 size += sep_size * ((num_digits - 1) / groups.back());
1619 writer.write_int(size, get_prefix(), specs,
1620 num_writer{abs_value, size, groups, sep});
1623 FMT_NORETURN
void on_error() {
1628 template <
typename Char>
struct str_writer {
1632 size_t size()
const {
return size_; }
1633 size_t width()
const {
1637 template <
typename It>
void operator()(It&& it)
const {
1638 it = copy_str<char_type>(s, s + size_, it);
1642 struct bytes_writer {
1645 size_t size()
const {
return bytes.
size(); }
1646 size_t width()
const {
return bytes.
size(); }
1648 template <
typename It>
void operator()(It&& it)
const {
1649 const char* data = bytes.
data();
1650 it = copy_str<char>(data, data + size(), it);
1654 template <
typename UIntPtr>
struct pointer_writer {
1658 size_t size()
const {
return to_unsigned(num_digits) + 2; }
1659 size_t width()
const {
return size(); }
1661 template <
typename It>
void operator()(It&& it)
const {
1662 *it++ =
static_cast<char_type
>(
'0');
1663 *it++ =
static_cast<char_type
>(
'x');
1664 it = format_uint<4, char_type>(it, value, num_digits);
1669 explicit basic_writer(Range out, locale_ref loc = locale_ref())
1670 : out_(out.begin()), locale_(loc) {}
1672 iterator out()
const {
return out_; }
1677 template <
typename F>
void write_padded(
const format_specs& specs, F&& f) {
1679 unsigned width = to_unsigned(specs.width);
1680 size_t size = f.size();
1681 size_t num_code_points = width != 0 ? f.width() : size;
1682 if (width <= num_code_points)
return f(reserve(size));
1683 size_t padding = width - num_code_points;
1684 size_t fill_size = specs.fill.size();
1685 auto&& it = reserve(size + padding * fill_size);
1686 if (specs.align == align::right) {
1687 it = fill(it, padding, specs.fill);
1689 }
else if (specs.align == align::center) {
1690 std::size_t left_padding = padding / 2;
1691 it = fill(it, left_padding, specs.fill);
1693 it = fill(it, padding - left_padding, specs.fill);
1696 it = fill(it, padding, specs.fill);
1700 void write(
int value) { write_decimal(value); }
1701 void write(
long value) { write_decimal(value); }
1702 void write(
long long value) { write_decimal(value); }
1704 void write(
unsigned value) { write_decimal(value); }
1705 void write(
unsigned long value) { write_decimal(value); }
1706 void write(
unsigned long long value) { write_decimal(value); }
1709 void write(int128_t value) { write_decimal(value); }
1710 void write(uint128_t value) { write_decimal(value); }
1713 template <
typename T,
typename Spec>
1714 void write_int(T value,
const Spec& spec) {
1715 handle_int_type_spec(spec.type, int_writer<T, Spec>(*
this, value, spec));
1718 template <
typename T, FMT_ENABLE_IF(std::is_
floating_po
int<T>::value)>
1719 void write(T value, format_specs specs = {}) {
1720 if (const_check(!is_supported_floating_point(value))) {
1723 float_specs fspecs = parse_float_type_spec(specs);
1724 fspecs.sign = specs.sign;
1725 if (std::signbit(value)) {
1726 fspecs.sign = sign::minus;
1728 }
else if (fspecs.sign == sign::minus) {
1729 fspecs.sign = sign::none;
1732 if (!std::isfinite(value)) {
1733 auto str = std::isinf(value) ? (fspecs.upper ?
"INF" :
"inf")
1734 : (fspecs.upper ?
"NAN" :
"nan");
1735 return write_padded(specs, nonfinite_writer<char_type>{fspecs.sign, str});
1738 if (specs.align == align::none) {
1739 specs.align = align::right;
1740 }
else if (specs.align == align::numeric) {
1742 auto&& it = reserve(1);
1743 *it++ =
static_cast<char_type
>(data::signs[fspecs.sign]);
1744 fspecs.sign = sign::none;
1745 if (specs.width != 0) --specs.width;
1747 specs.align = align::right;
1751 if (fspecs.format == float_format::hex) {
1752 if (fspecs.sign) buffer.push_back(data::signs[fspecs.sign]);
1753 snprintf_float(promote_float(value), specs.precision, fspecs, buffer);
1754 write_padded(specs, str_writer<char>{buffer.
data(), buffer.
size()});
1757 int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6;
1758 if (fspecs.format == float_format::exp) {
1759 if (precision == max_value<int>())
1764 if (const_check(std::is_same<T, float>())) fspecs.binary32 =
true;
1765 fspecs.use_grisu = use_grisu<T>();
1766 if (const_check(FMT_DEPRECATED_PERCENT) && fspecs.percent) value *= 100;
1767 int exp = format_float(promote_float(value), precision, fspecs, buffer);
1768 if (const_check(FMT_DEPRECATED_PERCENT) && fspecs.percent) {
1769 buffer.push_back(
'%');
1772 fspecs.precision = precision;
1773 char_type point = fspecs.locale ? decimal_point<char_type>(locale_)
1774 : static_cast<char_type>(
'.');
1775 write_padded(specs, float_writer<char_type>(buffer.
data(),
1776 static_cast<int>(buffer.
size()),
1777 exp, fspecs, point));
1780 void write(
char value) {
1781 auto&& it = reserve(1);
1785 template <
typename Char, FMT_ENABLE_IF(std::is_same<Char,
char_type>::value)>
1786 void write(Char value) {
1787 auto&& it = reserve(1);
1792 auto&& it = reserve(value.
size());
1793 it = copy_str<char_type>(value.begin(), value.end(), it);
1796 static_assert(std::is_same<char_type, wchar_t>::value,
"");
1797 auto&& it = reserve(value.
size());
1798 it = std::copy(value.begin(), value.end(), it);
1801 template <
typename Char>
1802 void write(
const Char* s, std::size_t size,
const format_specs& specs) {
1803 write_padded(specs, str_writer<Char>{s, size});
1806 template <
typename Char>
1808 const Char* data = s.
data();
1809 std::size_t size = s.
size();
1810 if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
1811 size = code_point_index(s, to_unsigned(specs.precision));
1812 write(data, size, specs);
1815 void write_bytes(
string_view bytes,
const format_specs& specs) {
1816 write_padded(specs, bytes_writer{bytes});
1819 template <
typename UIntPtr>
1820 void write_pointer(UIntPtr value,
const format_specs* specs) {
1821 int num_digits = count_digits<4>(value);
1822 auto pw = pointer_writer<UIntPtr>{value, num_digits};
1823 if (!specs)
return pw(reserve(to_unsigned(num_digits) + 2));
1824 format_specs specs_copy = *specs;
1825 if (specs_copy.align == align::none) specs_copy.align = align::right;
1826 write_padded(specs_copy, pw);
1830using writer = basic_writer<buffer_range<char>>;
1832template <
typename T>
struct is_integral : std::is_integral<T> {};
1833template <>
struct is_integral<int128_t> : std::true_type {};
1834template <>
struct is_integral<uint128_t> : std::true_type {};
1836template <
typename Range,
typename ErrorHandler =
internal::error_handler>
1837class arg_formatter_base {
1839 using char_type =
typename Range::value_type;
1840 using iterator =
typename Range::iterator;
1841 using format_specs = basic_format_specs<char_type>;
1844 using writer_type = basic_writer<Range>;
1845 writer_type writer_;
1846 format_specs* specs_;
1848 struct char_writer {
1851 size_t size()
const {
return 1; }
1852 size_t width()
const {
return 1; }
1854 template <
typename It>
void operator()(It&& it)
const { *it++ = value; }
1857 void write_char(char_type value) {
1859 writer_.write_padded(*specs_, char_writer{value});
1861 writer_.write(value);
1864 void write_pointer(
const void* p) {
1865 writer_.write_pointer(internal::to_uintptr(p), specs_);
1869 writer_type& writer() {
return writer_; }
1870 FMT_DEPRECATED format_specs* spec() {
return specs_; }
1871 format_specs* specs() {
return specs_; }
1872 iterator out() {
return writer_.out(); }
1874 void write(
bool value) {
1876 specs_ ? writer_.write(sv, *specs_) : writer_.write(sv);
1879 void write(
const char_type* value) {
1883 auto length = std::char_traits<char_type>::length(value);
1885 specs_ ? writer_.write(sv, *specs_) : writer_.write(sv);
1890 arg_formatter_base(Range r, format_specs* s, locale_ref loc)
1891 : writer_(r, loc), specs_(s) {}
1893 iterator operator()(monostate) {
1894 FMT_ASSERT(
false,
"invalid argument type");
1898 template <
typename T, FMT_ENABLE_IF(is_
integral<T>::value)>
1899 iterator operator()(T value) {
1901 writer_.write_int(value, *specs_);
1903 writer_.write(value);
1907 iterator operator()(char_type value) {
1908 internal::handle_char_specs(
1909 specs_, char_spec_handler(*
this,
static_cast<char_type
>(value)));
1913 iterator operator()(
bool value) {
1914 if (specs_ && specs_->type)
return (*
this)(value ? 1 : 0);
1919 template <
typename T, FMT_ENABLE_IF(std::is_
floating_po
int<T>::value)>
1920 iterator operator()(T value) {
1921 if (const_check(is_supported_floating_point(value)))
1922 writer_.write(value, specs_ ? *specs_ : format_specs());
1924 FMT_ASSERT(
false,
"unsupported float argument type");
1928 struct char_spec_handler : ErrorHandler {
1929 arg_formatter_base& formatter;
1932 char_spec_handler(arg_formatter_base& f, char_type val)
1933 : formatter(f), value(val) {}
1936 if (formatter.specs_)
1937 formatter.writer_.write_int(value, *formatter.specs_);
1939 formatter.writer_.write(value);
1941 void on_char() { formatter.write_char(value); }
1944 struct cstring_spec_handler : internal::error_handler {
1945 arg_formatter_base& formatter;
1946 const char_type* value;
1948 cstring_spec_handler(arg_formatter_base& f,
const char_type* val)
1949 : formatter(f), value(val) {}
1951 void on_string() { formatter.write(value); }
1952 void on_pointer() { formatter.write_pointer(value); }
1955 iterator operator()(
const char_type* value) {
1956 if (!specs_)
return write(value), out();
1957 internal::handle_cstring_type_spec(specs_->type,
1958 cstring_spec_handler(*
this, value));
1964 internal::check_string_type_spec(specs_->type, internal::error_handler());
1965 writer_.write(value, *specs_);
1967 writer_.write(value);
1972 iterator operator()(
const void* value) {
1974 check_pointer_type_spec(specs_->type, internal::error_handler());
1975 write_pointer(value);
1980template <
typename Char> FMT_CONSTEXPR
bool is_name_start(Char c) {
1981 return (
'a' <= c && c <=
'z') || (
'A' <= c && c <=
'Z') ||
'_' == c;
1986template <
typename Char,
typename ErrorHandler>
1987FMT_CONSTEXPR
int parse_nonnegative_int(
const Char*& begin,
const Char* end,
1988 ErrorHandler&& eh) {
1989 FMT_ASSERT(begin != end &&
'0' <= *begin && *begin <=
'9',
"");
1992 constexpr unsigned max_int = max_value<int>();
1993 unsigned big = max_int / 10;
1997 value = max_int + 1;
2000 value = value * 10 + unsigned(*begin -
'0');
2002 }
while (begin != end &&
'0' <= *begin && *begin <=
'9');
2003 if (value > max_int) eh.on_error(
"number is too big");
2004 return static_cast<int>(value);
2007template <
typename Context>
class custom_formatter {
2009 using char_type =
typename Context::char_type;
2017 : parse_ctx_(parse_ctx), ctx_(ctx) {}
2019 bool operator()(
typename basic_format_arg<Context>::handle h)
const {
2020 h.format(parse_ctx_, ctx_);
2024 template <
typename T>
bool operator()(T)
const {
return false; }
2027template <
typename T>
2029 bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value &&
2030 !std::is_same<T, char>::value &&
2031 !std::is_same<T, wchar_t>::value>;
2033template <
typename ErrorHandler>
class width_checker {
2035 explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {}
2037 template <
typename T, FMT_ENABLE_IF(is_
integer<T>::value)>
2038 FMT_CONSTEXPR
unsigned long long operator()(T value) {
2039 if (is_negative(value)) handler_.on_error(
"negative width");
2040 return static_cast<unsigned long long>(value);
2043 template <
typename T, FMT_ENABLE_IF(!is_
integer<T>::value)>
2044 FMT_CONSTEXPR
unsigned long long operator()(T) {
2045 handler_.on_error(
"width is not integer");
2050 ErrorHandler& handler_;
2053template <
typename ErrorHandler>
class precision_checker {
2055 explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {}
2057 template <
typename T, FMT_ENABLE_IF(is_
integer<T>::value)>
2058 FMT_CONSTEXPR
unsigned long long operator()(T value) {
2059 if (is_negative(value)) handler_.on_error(
"negative precision");
2060 return static_cast<unsigned long long>(value);
2063 template <
typename T, FMT_ENABLE_IF(!is_
integer<T>::value)>
2064 FMT_CONSTEXPR
unsigned long long operator()(T) {
2065 handler_.on_error(
"precision is not integer");
2070 ErrorHandler& handler_;
2074template <
typename Char>
class specs_setter {
2076 explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char>& specs)
2079 FMT_CONSTEXPR specs_setter(
const specs_setter& other)
2080 : specs_(other.specs_) {}
2082 FMT_CONSTEXPR
void on_align(align_t align) { specs_.align = align; }
2086 FMT_CONSTEXPR
void on_plus() { specs_.sign = sign::plus; }
2087 FMT_CONSTEXPR
void on_minus() { specs_.sign = sign::minus; }
2088 FMT_CONSTEXPR
void on_space() { specs_.sign = sign::space; }
2089 FMT_CONSTEXPR
void on_hash() { specs_.alt =
true; }
2091 FMT_CONSTEXPR
void on_zero() {
2092 specs_.align = align::numeric;
2093 specs_.fill[0] = Char(
'0');
2096 FMT_CONSTEXPR
void on_width(
int width) { specs_.width = width; }
2097 FMT_CONSTEXPR
void on_precision(
int precision) {
2098 specs_.precision = precision;
2100 FMT_CONSTEXPR
void end_precision() {}
2102 FMT_CONSTEXPR
void on_type(Char type) {
2103 specs_.type =
static_cast<char>(type);
2107 basic_format_specs<Char>& specs_;
2110template <
typename ErrorHandler>
class numeric_specs_checker {
2112 FMT_CONSTEXPR numeric_specs_checker(ErrorHandler& eh, internal::type arg_type)
2113 : error_handler_(eh), arg_type_(arg_type) {}
2115 FMT_CONSTEXPR
void require_numeric_argument() {
2116 if (!is_arithmetic_type(arg_type_))
2117 error_handler_.on_error(
"format specifier requires numeric argument");
2120 FMT_CONSTEXPR
void check_sign() {
2121 require_numeric_argument();
2122 if (is_integral_type(arg_type_) && arg_type_ != type::int_type &&
2123 arg_type_ != type::long_long_type && arg_type_ != type::char_type) {
2124 error_handler_.on_error(
"format specifier requires signed argument");
2128 FMT_CONSTEXPR
void check_precision() {
2129 if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type)
2130 error_handler_.on_error(
"precision not allowed for this argument type");
2134 ErrorHandler& error_handler_;
2135 internal::type arg_type_;
2140template <
typename Handler>
class specs_checker :
public Handler {
2142 FMT_CONSTEXPR specs_checker(
const Handler& handler, internal::type arg_type)
2143 : Handler(handler), checker_(*this, arg_type) {}
2145 FMT_CONSTEXPR specs_checker(
const specs_checker& other)
2146 : Handler(other), checker_(*this, other.arg_type_) {}
2148 FMT_CONSTEXPR
void on_align(align_t align) {
2149 if (align == align::numeric) checker_.require_numeric_argument();
2150 Handler::on_align(align);
2153 FMT_CONSTEXPR
void on_plus() {
2154 checker_.check_sign();
2158 FMT_CONSTEXPR
void on_minus() {
2159 checker_.check_sign();
2160 Handler::on_minus();
2163 FMT_CONSTEXPR
void on_space() {
2164 checker_.check_sign();
2165 Handler::on_space();
2168 FMT_CONSTEXPR
void on_hash() {
2169 checker_.require_numeric_argument();
2173 FMT_CONSTEXPR
void on_zero() {
2174 checker_.require_numeric_argument();
2178 FMT_CONSTEXPR
void end_precision() { checker_.check_precision(); }
2181 numeric_specs_checker<Handler> checker_;
2184template <
template <
typename>
class Handler,
typename FormatArg,
2185 typename ErrorHandler>
2186FMT_CONSTEXPR
int get_dynamic_spec(FormatArg arg, ErrorHandler eh) {
2187 unsigned long long value = visit_format_arg(Handler<ErrorHandler>(eh), arg);
2188 if (value > to_unsigned(max_value<int>())) eh.on_error(
"number is too big");
2189 return static_cast<int>(value);
2194template <
typename Context>
2195FMT_CONSTEXPR
typename Context::format_arg get_arg(Context& ctx,
int id) {
2196 auto arg = ctx.arg(
id);
2197 if (!arg) ctx.on_error(
"argument index out of range");
2202template <
typename ParseContext,
typename Context>
2203class specs_handler :
public specs_setter<typename Context::char_type> {
2205 using char_type =
typename Context::char_type;
2207 FMT_CONSTEXPR specs_handler(basic_format_specs<char_type>& specs,
2208 ParseContext& parse_ctx, Context& ctx)
2209 : specs_setter<char_type>(specs),
2210 parse_context_(parse_ctx),
2213 template <
typename Id> FMT_CONSTEXPR
void on_dynamic_width(Id arg_id) {
2214 this->specs_.width = get_dynamic_spec<width_checker>(
2215 get_arg(arg_id), context_.error_handler());
2218 template <
typename Id> FMT_CONSTEXPR
void on_dynamic_precision(Id arg_id) {
2219 this->specs_.precision = get_dynamic_spec<precision_checker>(
2220 get_arg(arg_id), context_.error_handler());
2223 void on_error(
const char* message) { context_.on_error(message); }
2227 using format_arg =
typename Context::format_arg;
2229 FMT_CONSTEXPR format_arg get_arg(auto_id) {
2230 return internal::get_arg(context_, parse_context_.next_arg_id());
2233 FMT_CONSTEXPR format_arg get_arg(
int arg_id) {
2234 parse_context_.check_arg_id(arg_id);
2235 return internal::get_arg(context_, arg_id);
2239 parse_context_.check_arg_id(arg_id);
2240 return context_.arg(arg_id);
2243 ParseContext& parse_context_;
2247enum class arg_id_kind { none, index, name };
2250template <
typename Char>
struct arg_ref {
2251 FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {}
2253 FMT_CONSTEXPR
explicit arg_ref(
int index)
2254 : kind(arg_id_kind::index), val(index) {}
2256 : kind(arg_id_kind::name), val(name) {}
2258 FMT_CONSTEXPR arg_ref& operator=(
int idx) {
2259 kind = arg_id_kind::index;
2266 FMT_CONSTEXPR value(
int id = 0) : index{id} {}
2277template <
typename Char>
2278struct dynamic_format_specs : basic_format_specs<Char> {
2279 arg_ref<Char> width_ref;
2280 arg_ref<Char> precision_ref;
2285template <
typename ParseContext>
2286class dynamic_specs_handler
2287 :
public specs_setter<typename ParseContext::char_type> {
2289 using char_type =
typename ParseContext::char_type;
2291 FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs<char_type>& specs,
2293 : specs_setter<char_type>(specs), specs_(specs), context_(ctx) {}
2295 FMT_CONSTEXPR dynamic_specs_handler(
const dynamic_specs_handler& other)
2296 : specs_setter<char_type>(other),
2297 specs_(other.specs_),
2298 context_(other.context_) {}
2300 template <
typename Id> FMT_CONSTEXPR
void on_dynamic_width(Id arg_id) {
2301 specs_.width_ref = make_arg_ref(arg_id);
2304 template <
typename Id> FMT_CONSTEXPR
void on_dynamic_precision(Id arg_id) {
2305 specs_.precision_ref = make_arg_ref(arg_id);
2308 FMT_CONSTEXPR
void on_error(
const char* message) {
2309 context_.on_error(message);
2313 using arg_ref_type = arg_ref<char_type>;
2315 FMT_CONSTEXPR arg_ref_type make_arg_ref(
int arg_id) {
2316 context_.check_arg_id(arg_id);
2317 return arg_ref_type(arg_id);
2320 FMT_CONSTEXPR arg_ref_type make_arg_ref(auto_id) {
2321 return arg_ref_type(context_.next_arg_id());
2325 context_.check_arg_id(arg_id);
2327 context_.begin(), to_unsigned(context_.end() - context_.begin()));
2328 return arg_ref_type(arg_id);
2331 dynamic_format_specs<char_type>& specs_;
2332 ParseContext& context_;
2335template <
typename Char,
typename IDHandler>
2336FMT_CONSTEXPR
const Char* parse_arg_id(
const Char* begin,
const Char* end,
2337 IDHandler&& handler) {
2338 FMT_ASSERT(begin != end,
"");
2340 if (c ==
'}' || c ==
':') {
2344 if (c >=
'0' && c <=
'9') {
2347 index = parse_nonnegative_int(begin, end, handler);
2350 if (begin == end || (*begin !=
'}' && *begin !=
':'))
2351 handler.on_error(
"invalid format string");
2356 if (!is_name_start(c)) {
2357 handler.on_error(
"invalid format string");
2363 }
while (it != end && (is_name_start(c = *it) || (
'0' <= c && c <=
'9')));
2369template <
typename SpecHandler,
typename Char>
struct width_adapter {
2370 explicit FMT_CONSTEXPR width_adapter(SpecHandler& h) : handler(h) {}
2372 FMT_CONSTEXPR
void operator()() { handler.on_dynamic_width(auto_id()); }
2373 FMT_CONSTEXPR
void operator()(
int id) { handler.on_dynamic_width(
id); }
2375 handler.on_dynamic_width(
id);
2378 FMT_CONSTEXPR
void on_error(
const char* message) {
2379 handler.on_error(message);
2382 SpecHandler& handler;
2386template <
typename SpecHandler,
typename Char>
struct precision_adapter {
2387 explicit FMT_CONSTEXPR precision_adapter(SpecHandler& h) : handler(h) {}
2389 FMT_CONSTEXPR
void operator()() { handler.on_dynamic_precision(auto_id()); }
2390 FMT_CONSTEXPR
void operator()(
int id) { handler.on_dynamic_precision(
id); }
2392 handler.on_dynamic_precision(
id);
2395 FMT_CONSTEXPR
void on_error(
const char* message) {
2396 handler.on_error(message);
2399 SpecHandler& handler;
2402template <
typename Char>
2403FMT_CONSTEXPR
const Char* next_code_point(
const Char* begin,
const Char* end) {
2404 if (const_check(
sizeof(Char) != 1) || (*begin & 0x80) == 0)
return begin + 1;
2407 }
while (begin != end && (*begin & 0xc0) == 0x80);
2412template <
typename Char,
typename Handler>
2413FMT_CONSTEXPR
const Char* parse_align(
const Char* begin,
const Char* end,
2414 Handler&& handler) {
2415 FMT_ASSERT(begin != end,
"");
2416 auto align = align::none;
2417 auto p = next_code_point(begin, end);
2418 if (p == end) p = begin;
2420 switch (
static_cast<char>(*p)) {
2422 align = align::left;
2425 align = align::right;
2427#if FMT_NUMERIC_ALIGN
2429 align = align::numeric;
2433 align = align::center;
2436 if (align != align::none) {
2440 return handler.on_error(
"invalid fill character '{'"), begin;
2445 handler.on_align(align);
2447 }
else if (p == begin) {
2455template <
typename Char,
typename Handler>
2456FMT_CONSTEXPR
const Char* parse_width(
const Char* begin,
const Char* end,
2457 Handler&& handler) {
2458 FMT_ASSERT(begin != end,
"");
2459 if (
'0' <= *begin && *begin <=
'9') {
2460 handler.on_width(parse_nonnegative_int(begin, end, handler));
2461 }
else if (*begin ==
'{') {
2464 begin = parse_arg_id(begin, end, width_adapter<Handler, Char>(handler));
2465 if (begin == end || *begin !=
'}')
2466 return handler.on_error(
"invalid format string"), begin;
2472template <
typename Char,
typename Handler>
2473FMT_CONSTEXPR
const Char* parse_precision(
const Char* begin,
const Char* end,
2474 Handler&& handler) {
2476 auto c = begin != end ? *begin : Char();
2477 if (
'0' <= c && c <=
'9') {
2478 handler.on_precision(parse_nonnegative_int(begin, end, handler));
2479 }
else if (c ==
'{') {
2483 parse_arg_id(begin, end, precision_adapter<Handler, Char>(handler));
2485 if (begin == end || *begin++ !=
'}')
2486 return handler.on_error(
"invalid format string"), begin;
2488 return handler.on_error(
"missing precision specifier"), begin;
2490 handler.end_precision();
2496template <
typename Char,
typename SpecHandler>
2497FMT_CONSTEXPR
const Char* parse_format_specs(
const Char* begin,
const Char* end,
2498 SpecHandler&& handler) {
2499 if (begin == end || *begin ==
'}')
return begin;
2501 begin = parse_align(begin, end, handler);
2502 if (begin == end)
return begin;
2505 switch (
static_cast<char>(*begin)) {
2519 if (begin == end)
return begin;
2521 if (*begin ==
'#') {
2523 if (++begin == end)
return begin;
2527 if (*begin ==
'0') {
2529 if (++begin == end)
return begin;
2532 begin = parse_width(begin, end, handler);
2533 if (begin == end)
return begin;
2536 if (*begin ==
'.') {
2537 begin = parse_precision(begin, end, handler);
2541 if (begin != end && *begin !=
'}') handler.on_type(*begin++);
2546template <
bool IS_CONSTEXPR,
typename T,
typename Ptr = const T*>
2547FMT_CONSTEXPR
bool find(Ptr first, Ptr last, T value, Ptr& out) {
2548 for (out = first; out != last; ++out) {
2549 if (*out == value)
return true;
2555inline bool find<false, char>(
const char* first,
const char* last,
char value,
2557 out =
static_cast<const char*
>(
2558 std::memchr(first, value, internal::to_unsigned(last - first)));
2559 return out !=
nullptr;
2562template <
typename Handler,
typename Char>
struct id_adapter {
2563 FMT_CONSTEXPR
void operator()() { handler.on_arg_id(); }
2564 FMT_CONSTEXPR
void operator()(
int id) { handler.on_arg_id(
id); }
2566 handler.on_arg_id(
id);
2568 FMT_CONSTEXPR
void on_error(
const char* message) {
2569 handler.on_error(message);
2574template <
bool IS_CONSTEXPR,
typename Char,
typename Handler>
2576 Handler&& handler) {
2578 FMT_CONSTEXPR
void operator()(
const Char* begin,
const Char* end) {
2579 if (begin == end)
return;
2581 const Char* p =
nullptr;
2582 if (!find<IS_CONSTEXPR>(begin, end,
'}', p))
2583 return handler_.on_text(begin, end);
2585 if (p == end || *p !=
'}')
2586 return handler_.on_error(
"unmatched '}' in format string");
2587 handler_.on_text(begin, p);
2593 auto begin = format_str.
data();
2594 auto end = begin + format_str.
size();
2595 while (begin != end) {
2598 const Char* p = begin;
2599 if (*begin !=
'{' && !find<IS_CONSTEXPR>(begin + 1, end,
'{', p))
2600 return write(begin, end);
2603 if (p == end)
return handler.on_error(
"invalid format string");
2604 if (
static_cast<char>(*p) ==
'}') {
2605 handler.on_arg_id();
2606 handler.on_replacement_field(p);
2607 }
else if (*p ==
'{') {
2608 handler.on_text(p, p + 1);
2610 p = parse_arg_id(p, end, id_adapter<Handler, Char>{handler});
2611 Char c = p != end ? *p : Char();
2613 handler.on_replacement_field(p);
2614 }
else if (c ==
':') {
2615 p = handler.on_format_specs(p + 1, end);
2616 if (p == end || *p !=
'}')
2617 return handler.on_error(
"unknown format specifier");
2619 return handler.on_error(
"missing '}' in format string");
2626template <
typename T,
typename ParseContext>
2627FMT_CONSTEXPR
const typename ParseContext::char_type* parse_format_specs(
2628 ParseContext& ctx) {
2629 using char_type =
typename ParseContext::char_type;
2630 using context = buffer_context<char_type>;
2632 conditional_t<internal::mapped_type_constant<T, context>::value !=
2634 decltype(arg_mapper<context>().map(std::declval<T>())), T>;
2635 auto f = conditional_t<has_formatter<mapped_type, context>::value,
2636 formatter<mapped_type, char_type>,
2637 internal::fallback_formatter<T, char_type>>();
2638 return f.parse(ctx);
2641template <
typename Char,
typename ErrorHandler,
typename... Args>
2642class format_string_checker {
2644 explicit FMT_CONSTEXPR format_string_checker(
2647 context_(format_str, eh),
2648 parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {}
2650 FMT_CONSTEXPR
void on_text(
const Char*,
const Char*) {}
2652 FMT_CONSTEXPR
void on_arg_id() {
2653 arg_id_ = context_.next_arg_id();
2656 FMT_CONSTEXPR
void on_arg_id(
int id) {
2658 context_.check_arg_id(
id);
2662 on_error(
"compile-time checks don't support named arguments");
2665 FMT_CONSTEXPR
void on_replacement_field(
const Char*) {}
2667 FMT_CONSTEXPR
const Char* on_format_specs(
const Char* begin,
const Char*) {
2668 advance_to(context_, begin);
2669 return arg_id_ < num_args ? parse_funcs_[arg_id_](context_) : begin;
2672 FMT_CONSTEXPR
void on_error(
const char* message) {
2673 context_.on_error(message);
2678 enum { num_args =
sizeof...(Args) };
2680 FMT_CONSTEXPR
void check_arg_id() {
2681 if (arg_id_ >= num_args) context_.on_error(
"argument index out of range");
2685 using parse_func =
const Char* (*)(parse_context_type&);
2688 parse_context_type context_;
2689 parse_func parse_funcs_[num_args > 0 ? num_args : 1];
2692template <
typename Char,
typename ErrorHandler,
typename... Args>
2694 ErrorHandler eh = ErrorHandler()) {
2695 format_string_checker<Char, ErrorHandler, Args...> checker(s, eh);
2696 parse_format_string<true>(s, checker);
2700template <
typename... Args,
typename S,
2701 enable_if_t<(is_compile_string<S>::value),
int>>
2702void check_format_string(S format_str) {
2703 FMT_CONSTEXPR_DECL
bool invalid_format = internal::do_check_format_string<
2704 typename S::char_type, internal::error_handler,
2705 remove_const_t<remove_reference_t<Args>>...>(to_string_view(format_str));
2706 (void)invalid_format;
2709template <
template <
typename>
class Handler,
typename Context>
2710void handle_dynamic_spec(
int& value, arg_ref<typename Context::char_type> ref,
2713 case arg_id_kind::none:
2715 case arg_id_kind::index:
2716 value = internal::get_dynamic_spec<Handler>(ctx.arg(ref.val.index),
2717 ctx.error_handler());
2719 case arg_id_kind::name:
2720 value = internal::get_dynamic_spec<Handler>(ctx.arg(ref.val.name),
2721 ctx.error_handler());
2728FMT_API
void format_error_code(buffer<char>& out,
int error_code,
2731FMT_API
void report_error(format_func func,
int error_code,
2735template <
typename Range>
2736using basic_writer FMT_DEPRECATED_ALIAS = internal::basic_writer<Range>;
2737using writer FMT_DEPRECATED_ALIAS = internal::writer;
2738using wwriter FMT_DEPRECATED_ALIAS =
2739 internal::basic_writer<buffer_range<wchar_t>>;
2742template <
typename Range>
2745 using char_type =
typename Range::value_type;
2746 using base = internal::arg_formatter_base<Range>;
2747 using context_type = basic_format_context<typename base::iterator, char_type>;
2753 using range = Range;
2754 using iterator =
typename base::iterator;
2755 using format_specs =
typename base::format_specs;
2767 format_specs* specs =
nullptr)
2768 : base(Range(ctx.out()), specs, ctx.locale()),
2770 parse_ctx_(parse_ctx) {}
2772 using base::operator();
2775 iterator
operator()(
typename basic_format_arg<context_type>::handle handle) {
2776 handle.format(*parse_ctx_, ctx_);
2793 system_error() : std::runtime_error(
""), error_code_(0) {}
2814 template <
typename... Args>
2816 : std::runtime_error(
"") {
2817 init(error_code, message, make_format_args(args...));
2825 int error_code()
const {
return error_code_; }
2849FMT_API
void report_system_error(
int error_code,
2857 enum { buffer_size = std::numeric_limits<unsigned long long>::digits10 + 3 };
2858 mutable char buffer_[buffer_size];
2862 char* format_decimal(
unsigned long long value) {
2863 char* ptr = buffer_ + (buffer_size - 1);
2864 while (value >= 100) {
2868 auto index =
static_cast<unsigned>((value % 100) * 2);
2870 *--ptr = internal::data::digits[index + 1];
2871 *--ptr = internal::data::digits[index];
2874 *--ptr =
static_cast<char>(
'0' + value);
2877 auto index =
static_cast<unsigned>(value * 2);
2878 *--ptr = internal::data::digits[index + 1];
2879 *--ptr = internal::data::digits[index];
2883 void format_signed(
long long value) {
2884 auto abs_value =
static_cast<unsigned long long>(value);
2885 bool negative = value < 0;
2886 if (negative) abs_value = 0 - abs_value;
2887 str_ = format_decimal(abs_value);
2888 if (negative) *--str_ =
'-';
2892 explicit format_int(
int value) { format_signed(value); }
2893 explicit format_int(
long value) { format_signed(value); }
2894 explicit format_int(
long long value) { format_signed(value); }
2895 explicit format_int(
unsigned value) : str_(format_decimal(value)) {}
2896 explicit format_int(
unsigned long value) : str_(format_decimal(value)) {}
2897 explicit format_int(
unsigned long long value) : str_(format_decimal(value)) {}
2901 return internal::to_unsigned(buffer_ - str_ + buffer_size - 1);
2908 const char*
data()
const {
return str_; }
2915 buffer_[buffer_size - 1] =
'\0';
2924 std::string
str()
const {
return std::string(str_,
size()); }
2929template <
typename T,
typename Char>
2930struct formatter<T, Char,
2931 enable_if_t<internal::type_constant<T, Char>::value !=
2932 internal::type::custom_type>> {
2933 FMT_CONSTEXPR formatter() =
default;
2937 template <
typename ParseContext>
2938 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
decltype(ctx.begin()) {
2939 using handler_type = internal::dynamic_specs_handler<ParseContext>;
2940 auto type = internal::type_constant<T, Char>::value;
2941 internal::specs_checker<handler_type> handler(handler_type(specs_, ctx),
2943 auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
2944 auto eh = ctx.error_handler();
2946 case internal::type::none_type:
2947 case internal::type::named_arg_type:
2948 FMT_ASSERT(
false,
"invalid argument type");
2950 case internal::type::int_type:
2951 case internal::type::uint_type:
2952 case internal::type::long_long_type:
2953 case internal::type::ulong_long_type:
2954 case internal::type::int128_type:
2955 case internal::type::uint128_type:
2956 case internal::type::bool_type:
2957 handle_int_type_spec(specs_.type,
2958 internal::int_type_checker<
decltype(eh)>(eh));
2960 case internal::type::char_type:
2962 &specs_, internal::char_specs_checker<
decltype(eh)>(specs_.type, eh));
2964 case internal::type::float_type:
2965 if (internal::const_check(FMT_USE_FLOAT)) {
2966 internal::parse_float_type_spec(specs_, eh);
2968 FMT_ASSERT(
false,
"float support disabled");
2971 case internal::type::double_type:
2972 if (internal::const_check(FMT_USE_DOUBLE)) {
2973 internal::parse_float_type_spec(specs_, eh);
2975 FMT_ASSERT(
false,
"double support disabled");
2978 case internal::type::long_double_type:
2979 if (internal::const_check(FMT_USE_LONG_DOUBLE)) {
2980 internal::parse_float_type_spec(specs_, eh);
2982 FMT_ASSERT(
false,
"long double support disabled");
2985 case internal::type::cstring_type:
2986 internal::handle_cstring_type_spec(
2987 specs_.type, internal::cstring_type_checker<
decltype(eh)>(eh));
2989 case internal::type::string_type:
2990 internal::check_string_type_spec(specs_.type, eh);
2992 case internal::type::pointer_type:
2993 internal::check_pointer_type_spec(specs_.type, eh);
2995 case internal::type::custom_type:
3003 template <
typename FormatContext>
3004 auto format(
const T& val, FormatContext& ctx) ->
decltype(ctx.out()) {
3005 internal::handle_dynamic_spec<internal::width_checker>(
3006 specs_.width, specs_.width_ref, ctx);
3007 internal::handle_dynamic_spec<internal::precision_checker>(
3008 specs_.precision, specs_.precision_ref, ctx);
3010 internal::output_range<
typename FormatContext::iterator,
3011 typename FormatContext::char_type>;
3013 internal::make_arg<FormatContext>(val));
3017 internal::dynamic_format_specs<Char> specs_;
3020#define FMT_FORMAT_AS(Type, Base) \
3021 template <typename Char> \
3022 struct formatter<Type, Char> : formatter<Base, Char> { \
3023 template <typename FormatContext> \
3024 auto format(Type const& val, FormatContext& ctx) -> decltype(ctx.out()) { \
3025 return formatter<Base, Char>::format(val, ctx); \
3029FMT_FORMAT_AS(
signed char,
int);
3030FMT_FORMAT_AS(
unsigned char,
unsigned);
3031FMT_FORMAT_AS(
short,
int);
3032FMT_FORMAT_AS(
unsigned short,
unsigned);
3033FMT_FORMAT_AS(
long,
long long);
3034FMT_FORMAT_AS(
unsigned long,
unsigned long long);
3035FMT_FORMAT_AS(Char*,
const Char*);
3037FMT_FORMAT_AS(std::nullptr_t,
const void*);
3040template <
typename Char>
3041struct formatter<void*, Char> : formatter<const void*, Char> {
3042 template <
typename FormatContext>
3043 auto format(
void* val, FormatContext& ctx) ->
decltype(ctx.out()) {
3044 return formatter<const void*, Char>::format(val, ctx);
3048template <
typename Char,
size_t N>
3049struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> {
3050 template <
typename FormatContext>
3051 auto format(
const Char* val, FormatContext& ctx) ->
decltype(ctx.out()) {
3052 return formatter<basic_string_view<Char>, Char>::format(val, ctx);
3066template <
typename Char =
char>
class dynamic_formatter {
3068 struct null_handler : internal::error_handler {
3069 void on_align(align_t) {}
3077 template <
typename ParseContext>
3078 auto parse(ParseContext& ctx) ->
decltype(ctx.begin()) {
3079 format_str_ = ctx.begin();
3081 internal::dynamic_specs_handler<ParseContext> handler(specs_, ctx);
3082 return parse_format_specs(ctx.begin(), ctx.end(), handler);
3085 template <
typename T,
typename FormatContext>
3086 auto format(
const T& val, FormatContext& ctx) ->
decltype(ctx.out()) {
3088 internal::specs_checker<null_handler> checker(
3090 internal::mapped_type_constant<T, FormatContext>::value);
3091 checker.on_align(specs_.align);
3092 switch (specs_.sign) {
3105 if (specs_.alt) checker.on_hash();
3106 if (specs_.precision >= 0) checker.end_precision();
3107 using range = internal::output_range<
typename FormatContext::iterator,
3108 typename FormatContext::char_type>;
3110 internal::make_arg<FormatContext>(val));
3115 template <
typename Context>
void handle_specs(Context& ctx) {
3116 internal::handle_dynamic_spec<internal::width_checker>(
3117 specs_.width, specs_.width_ref, ctx);
3118 internal::handle_dynamic_spec<internal::precision_checker>(
3119 specs_.precision, specs_.precision_ref, ctx);
3122 internal::dynamic_format_specs<Char> specs_;
3123 const Char* format_str_;
3126template <
typename Range,
typename Char>
3127typename basic_format_context<Range, Char>::format_arg
3130 format_arg arg = map_.find(name);
3131 if (arg.type() == internal::type::none_type)
3132 this->on_error(
"argument not found");
3136template <
typename Char,
typename ErrorHandler>
3137FMT_CONSTEXPR
void advance_to(
3142template <
typename ArgFormatter,
typename Char,
typename Context>
3143struct format_handler : internal::error_handler {
3144 using range =
typename ArgFormatter::range;
3148 internal::locale_ref loc)
3149 : parse_context(str), context(r.begin(),
format_args, loc) {}
3151 void on_text(
const Char* begin,
const Char* end) {
3152 auto size = internal::to_unsigned(end - begin);
3153 auto out = context.out();
3154 auto&& it = internal::reserve(out, size);
3155 it = std::copy_n(begin, size, it);
3156 context.advance_to(out);
3159 void get_arg(
int id) { arg = internal::get_arg(context,
id); }
3161 void on_arg_id() { get_arg(parse_context.next_arg_id()); }
3162 void on_arg_id(
int id) {
3163 parse_context.check_arg_id(
id);
3168 void on_replacement_field(
const Char* p) {
3169 advance_to(parse_context, p);
3171 visit_format_arg(ArgFormatter(context, &parse_context), arg));
3174 const Char* on_format_specs(
const Char* begin,
const Char* end) {
3175 advance_to(parse_context, begin);
3176 internal::custom_formatter<Context> f(parse_context, context);
3177 if (visit_format_arg(f, arg))
return parse_context.begin();
3178 basic_format_specs<Char> specs;
3179 using internal::specs_handler;
3181 internal::specs_checker<specs_handler<parse_context_t, Context>> handler(
3182 specs_handler<parse_context_t, Context>(specs, parse_context, context),
3184 begin = parse_format_specs(begin, end, handler);
3185 if (begin == end || *begin !=
'}') on_error(
"missing '}' in format string");
3186 advance_to(parse_context, begin);
3188 visit_format_arg(ArgFormatter(context, &parse_context, &specs), arg));
3194 basic_format_arg<Context> arg;
3198template <
typename ArgFormatter,
typename Char,
typename Context>
3199typename Context::iterator vformat_to(
3202 internal::locale_ref loc = internal::locale_ref()) {
3203 format_handler<ArgFormatter, Char, Context> h(out, format_str, args, loc);
3204 internal::parse_format_string<false>(format_str, h);
3205 return h.context.out();
3211template <
typename T>
inline const void* ptr(
const T* p) {
return p; }
3212template <
typename T>
inline const void* ptr(
const std::unique_ptr<T>& p) {
3215template <
typename T>
inline const void* ptr(
const std::shared_ptr<T>& p) {
3222 friend struct formatter<bytes>;
3228template <>
struct formatter<bytes> {
3229 template <
typename ParseContext>
3230 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
decltype(ctx.
begin()) {
3231 using handler_type = internal::dynamic_specs_handler<ParseContext>;
3232 internal::specs_checker<handler_type> handler(handler_type(specs_, ctx),
3233 internal::type::string_type);
3234 auto it = parse_format_specs(ctx.
begin(), ctx.
end(), handler);
3235 internal::check_string_type_spec(specs_.type, ctx.error_handler());
3239 template <
typename FormatContext>
3240 auto format(bytes b, FormatContext& ctx) ->
decltype(ctx.out()) {
3241 internal::handle_dynamic_spec<internal::width_checker>(
3242 specs_.width, specs_.width_ref, ctx);
3243 internal::handle_dynamic_spec<internal::precision_checker>(
3244 specs_.precision, specs_.precision_ref, ctx);
3246 internal::output_range<typename FormatContext::iterator, char>;
3247 internal::basic_writer<range_type> writer(range_type(ctx.out()));
3248 writer.write_bytes(b.data_, specs_);
3249 return writer.out();
3253 internal::dynamic_format_specs<char> specs_;
3256template <
typename It,
typename Char>
struct arg_join : internal::view {
3264template <
typename It,
typename Char>
3265struct formatter<arg_join<It, Char>, Char>
3266 : formatter<typename std::iterator_traits<It>::value_type, Char> {
3267 template <
typename FormatContext>
3268 auto format(
const arg_join<It, Char>& value, FormatContext& ctx)
3269 ->
decltype(ctx.out()) {
3270 using base = formatter<typename std::iterator_traits<It>::value_type, Char>;
3271 auto it = value.begin;
3272 auto out = ctx.out();
3273 if (it != value.end) {
3274 out = base::format(*it++, ctx);
3275 while (it != value.end) {
3276 out = std::copy(value.sep.begin(), value.sep.end(), out);
3278 out = base::format(*it++, ctx);
3289template <
typename It>
3290arg_join<It, char> join(It begin, It end,
string_view sep) {
3291 return {begin, end, sep};
3294template <
typename It>
3295arg_join<It, wchar_t> join(It begin, It end,
wstring_view sep) {
3296 return {begin, end, sep};
3315template <
typename Range>
3316arg_join<internal::iterator_t<const Range>,
char> join(
const Range& range,
3318 return join(std::begin(range), std::end(range), sep);
3321template <
typename Range>
3322arg_join<internal::iterator_t<const Range>,
wchar_t> join(
const Range& range,
3324 return join(std::begin(range), std::end(range), sep);
3338template <
typename T>
inline std::string to_string(
const T& value) {
3339 return format(
"{}", value);
3345template <
typename T>
inline std::wstring to_wstring(
const T& value) {
3346 return format(L
"{}", value);
3349template <
typename Char, std::
size_t SIZE>
3351 return std::basic_string<Char>(buf.
data(), buf.
size());
3354template <
typename Char>
3355typename buffer_context<Char>::iterator internal::vformat_to(
3358 using range = buffer_range<Char>;
3359 return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str),
3363template <
typename S,
typename Char =
char_t<S>,
3364 FMT_ENABLE_IF(
internal::is_
string<S>::value)>
3365inline typename buffer_context<Char>::iterator vformat_to(
3368 return internal::vformat_to(buf, to_string_view(format_str), args);
3371template <
typename S,
typename... Args, std::size_t SIZE = inline_buffer_size,
3372 typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
3373inline typename buffer_context<Char>::iterator format_to(
3375 internal::check_format_string<Args...>(format_str);
3376 using context = buffer_context<Char>;
3377 return internal::vformat_to(buf, to_string_view(format_str),
3378 make_format_args<context>(args...));
3381template <
typename OutputIt,
typename Char =
char>
3382using format_context_t = basic_format_context<OutputIt, Char>;
3384template <
typename OutputIt,
typename Char =
char>
3387template <
typename S,
typename OutputIt,
typename... Args,
3389 internal::is_output_iterator<OutputIt>::value &&
3390 !internal::is_contiguous_back_insert_iterator<OutputIt>::value)>
3391inline OutputIt vformat_to(
3392 OutputIt out,
const S& format_str,
3394 using range = internal::output_range<OutputIt, char_t<S>>;
3395 return vformat_to<arg_formatter<range>>(range(out),
3396 to_string_view(format_str), args);
3410template <
typename OutputIt,
typename S,
typename... Args,
3412 internal::is_output_iterator<OutputIt>::value &&
3413 !internal::is_contiguous_back_insert_iterator<OutputIt>::value &&
3414 internal::is_string<S>::value)>
3415inline OutputIt format_to(OutputIt out,
const S& format_str, Args&&... args) {
3416 internal::check_format_string<Args...>(format_str);
3417 using context = format_context_t<OutputIt, char_t<S>>;
3418 return vformat_to(out, to_string_view(format_str),
3419 make_format_args<context>(args...));
3422template <
typename OutputIt>
struct format_to_n_result {
3429template <
typename OutputIt,
typename Char =
typename OutputIt::value_type>
3430using format_to_n_context =
3431 format_context_t<internal::truncating_iterator<OutputIt>, Char>;
3433template <
typename OutputIt,
typename Char =
typename OutputIt::value_type>
3436template <
typename OutputIt,
typename Char,
typename... Args>
3438make_format_to_n_args(
const Args&... args) {
3443template <
typename OutputIt,
typename Char,
typename... Args,
3444 FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)>
3445inline format_to_n_result<OutputIt> vformat_to_n(
3448 auto it = vformat_to(internal::truncating_iterator<OutputIt>(out, n),
3450 return {it.base(), it.count()};
3460template <
typename OutputIt,
typename S,
typename... Args,
3461 FMT_ENABLE_IF(internal::is_string<S>::value&&
3462 internal::is_output_iterator<OutputIt>::value)>
3463inline format_to_n_result<OutputIt> format_to_n(OutputIt out, std::size_t n,
3464 const S& format_str,
3465 const Args&... args) {
3466 internal::check_format_string<Args...>(format_str);
3467 using context = format_to_n_context<OutputIt, char_t<S>>;
3468 return vformat_to_n(out, n, to_string_view(format_str),
3469 make_format_args<context>(args...));
3472template <
typename Char>
3473inline std::basic_string<Char> internal::vformat(
3477 internal::vformat_to(buffer, format_str, args);
3478 return to_string(buffer);
3485template <
typename... Args>
3486inline std::size_t formatted_size(
string_view format_str,
const Args&... args) {
3487 return format_to(internal::counting_iterator(), format_str, args...).count();
3490template <
typename Char, FMT_ENABLE_IF(std::is_same<Char,
wchar_t>::value)>
3492 wformat_args args) {
3494 internal::vformat_to(buffer, format_str, args);
3495 buffer.push_back(L
'\0');
3496 if (std::fputws(buffer.
data(), f) == -1)
3497 FMT_THROW(
system_error(errno,
"cannot write to file"));
3500template <
typename Char, FMT_ENABLE_IF(std::is_same<Char,
wchar_t>::value)>
3502 vprint(stdout, format_str, args);
3505#if FMT_USE_USER_DEFINED_LITERALS
3508# if FMT_USE_UDL_TEMPLATE
3509template <
typename Char, Char... CHARS>
class udl_formatter {
3511 template <
typename... Args>
3512 std::basic_string<Char> operator()(Args&&... args)
const {
3513 FMT_CONSTEXPR_DECL Char s[] = {CHARS...,
'\0'};
3514 FMT_CONSTEXPR_DECL
bool invalid_format =
3515 do_check_format_string<Char, error_handler, remove_cvref_t<Args>...>(
3517 (void)invalid_format;
3518 return format(s, std::forward<Args>(args)...);
3522template <
typename Char>
struct udl_formatter {
3525 template <
typename... Args>
3526 std::basic_string<Char> operator()(Args&&... args)
const {
3527 return format(str, std::forward<Args>(args)...);
3532template <
typename Char>
struct udl_arg {
3535 template <
typename T> named_arg<T, Char> operator=(T&& value)
const {
3536 return {str, std::forward<T>(value)};
3541template <
typename Char,
size_t N>
3543 const Char (&s)[N]) {
3547 N - ((std::char_traits<Char>::to_int_type(s[N - 1]) == 0) ? 1 : 0)};
3551template <
typename Char>
3553 const std_string_view<Char>& s) {
3554 return {s.
data(), s.size()};
3558inline namespace literals {
3559# if FMT_USE_UDL_TEMPLATE
3560# pragma GCC diagnostic push
3561# if FMT_CLANG_VERSION
3562# pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template"
3564template <
typename Char, Char... CHARS>
3565FMT_CONSTEXPR internal::udl_formatter<Char, CHARS...>
operator""_format() {
3568# pragma GCC diagnostic pop
3580FMT_CONSTEXPR internal::udl_formatter<char>
operator"" _format(
const char* s,
3584FMT_CONSTEXPR internal::udl_formatter<wchar_t>
operator"" _format(
3585 const wchar_t* s, std::size_t n) {
3600FMT_CONSTEXPR internal::udl_arg<char>
operator"" _a(
const char* s,
3604FMT_CONSTEXPR internal::udl_arg<wchar_t>
operator"" _a(
const wchar_t* s,
3612#define FMT_STRING_IMPL(s, ...) \
3615 struct FMT_COMPILE_STRING : fmt::compile_string { \
3616 using char_type = fmt::remove_cvref_t<decltype(s[0])>; \
3617 FMT_MAYBE_UNUSED __VA_ARGS__ FMT_CONSTEXPR \
3618 operator fmt::basic_string_view<char_type>() const { \
3619 return fmt::internal::compile_string_to_view<char_type>(s); \
3622 return FMT_COMPILE_STRING(); \
3635#define FMT_STRING(s) FMT_STRING_IMPL(s, )
3637#if defined(FMT_STRING_ALIAS) && FMT_STRING_ALIAS
3638# define fmt(s) FMT_STRING_IMPL(s, [[deprecated]])
3641#ifdef FMT_HEADER_ONLY
3642# define FMT_FUNC inline
3643# include "format-inl.h"
FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT
Definition: core.h:575
FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT
Definition: core.h:568
FMT_CONSTEXPR void advance_to(iterator it)
Definition: core.h:578
void grow(std::size_t size) FMT_OVERRIDE
Definition: format.h:700
basic_memory_buffer & operator=(basic_memory_buffer &&other) FMT_NOEXCEPT
Definition: format.h:688
basic_memory_buffer(basic_memory_buffer &&other) FMT_NOEXCEPT
Definition: format.h:681
FMT_CONSTEXPR size_t size() const
Definition: core.h:397
FMT_CONSTEXPR const Char * data() const
Definition: core.h:394
void append(const U *begin, const U *end)
Definition: format.h:557
void set(T *buf_data, std::size_t buf_capacity) FMT_NOEXCEPT
Definition: core.h:661
void resize(std::size_t new_size)
Definition: core.h:698
std::size_t capacity() const FMT_NOEXCEPT
Definition: core.h:687
std::size_t size() const FMT_NOEXCEPT
Definition: core.h:684
T * data() FMT_NOEXCEPT
Definition: core.h:690
Definition: format.h:2786
system_error(int error_code, string_view message, const Args &... args)
Definition: format.h:2815