33 #ifndef FMTQUILL_FORMAT_H_ 34 #define FMTQUILL_FORMAT_H_ 36 #ifndef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES 37 # define _LIBCPP_REMOVE_TRANSITIVE_INCLUDES 38 # define FMTQUILL_REMOVE_TRANSITIVE_INCLUDES 43 #if defined(__GNUC__) || defined(__clang__) || defined(__MINGW32__) 44 #pragma GCC diagnostic push 45 #pragma GCC diagnostic ignored "-Wfloat-equal" 48 #ifndef FMTQUILL_MODULE 55 # if defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI) 61 # include <system_error> 64 # if FMTQUILL_HAS_INCLUDE(<bit>) && FMTQUILL_CPLUSPLUS > 201703L 69 # if FMTQUILL_HAS_INCLUDE(<string_view>) && \ 70 (FMTQUILL_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION)) 71 # include <string_view> 72 # define FMTQUILL_USE_STRING_VIEW 75 # if FMTQUILL_MSC_VERSION 78 #endif // FMTQUILL_MODULE 80 #if defined(FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS) 82 #elif defined(__NVCOMPILER) 83 # define FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 0 84 #elif FMTQUILL_GCC_VERSION >= 903 && FMTQUILL_CPLUSPLUS >= 201709L 85 # define FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 1 86 #elif defined(__cpp_nontype_template_args) && \ 87 __cpp_nontype_template_args >= 201911L 88 # define FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 1 89 #elif FMTQUILL_CLANG_VERSION >= 1200 && FMTQUILL_CPLUSPLUS >= 202002L 90 # define FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 1 92 # define FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 0 95 #if defined __cpp_inline_variables && __cpp_inline_variables >= 201606L 96 # define FMTQUILL_INLINE_VARIABLE inline 98 # define FMTQUILL_INLINE_VARIABLE 102 #ifdef FMTQUILL_USE_RTTI 104 #elif defined(__GXX_RTTI) || FMTQUILL_HAS_FEATURE(cxx_rtti) || defined(_CPPRTTI) || \ 105 defined(__INTEL_RTTI__) || defined(__RTTI) 107 # define FMTQUILL_USE_RTTI 1 109 # define FMTQUILL_USE_RTTI 0 113 #if defined(FMTQUILL_LIB_EXPORT) || defined(FMTQUILL_SHARED) 114 # define FMTQUILL_SO_VISIBILITY(value) FMTQUILL_VISIBILITY(value) 116 # define FMTQUILL_SO_VISIBILITY(value) 119 #if FMTQUILL_GCC_VERSION || FMTQUILL_CLANG_VERSION 120 # define FMTQUILL_NOINLINE __attribute__((noinline)) 122 # define FMTQUILL_NOINLINE 128 using iterator_category = output_iterator_tag;
129 using value_type = T;
130 using difference_type =
131 decltype(static_cast<int*>(
nullptr) - static_cast<int*>(
nullptr));
132 using pointer = void;
133 using reference = void;
137 #ifndef FMTQUILL_THROW 138 # if FMTQUILL_USE_EXCEPTIONS 139 # if FMTQUILL_MSC_VERSION || defined(__NVCC__) 140 FMTQUILL_BEGIN_NAMESPACE
142 template <
typename Exception>
inline void do_throw(
const Exception& x) {
145 volatile bool b =
true;
149 FMTQUILL_END_NAMESPACE
150 # define FMTQUILL_THROW(x) detail::do_throw(x) 152 # define FMTQUILL_THROW(x) throw x 155 # define FMTQUILL_THROW(x) \ 156 ::fmtquill::detail::assert_fail(__FILE__, __LINE__, (x).what()) 157 # endif // FMTQUILL_USE_EXCEPTIONS 158 #endif // FMTQUILL_THROW 164 #if !defined(FMTQUILL_REDUCE_INT_INSTANTIATIONS) 165 # define FMTQUILL_REDUCE_INT_INSTANTIATIONS 0 168 FMTQUILL_BEGIN_NAMESPACE
170 template <
typename Char,
typename Traits,
typename Allocator>
178 #if !FMTQUILL_MSC_VERSION 179 # if FMTQUILL_HAS_BUILTIN(__builtin_clz) || FMTQUILL_GCC_VERSION || FMTQUILL_ICC_VERSION 180 # define FMTQUILL_BUILTIN_CLZ(n) __builtin_clz(n) 182 # if FMTQUILL_HAS_BUILTIN(__builtin_clzll) || FMTQUILL_GCC_VERSION || FMTQUILL_ICC_VERSION 183 # define FMTQUILL_BUILTIN_CLZLL(n) __builtin_clzll(n) 190 #if FMTQUILL_MSC_VERSION && !defined(FMTQUILL_BUILTIN_CLZLL) 193 # pragma intrinsic(_BitScanReverse) 195 # pragma intrinsic(_BitScanReverse64) 199 inline auto clz(uint32_t x) ->
int {
200 FMTQUILL_ASSERT(x != 0,
"");
201 FMTQUILL_MSC_WARNING(suppress : 6102)
203 _BitScanReverse(&r, x);
204 return 31 ^
static_cast<int>(r);
206 # define FMTQUILL_BUILTIN_CLZ(n) detail::clz(n) 208 inline auto clzll(uint64_t x) ->
int {
209 FMTQUILL_ASSERT(x != 0,
"");
210 FMTQUILL_MSC_WARNING(suppress : 6102)
213 _BitScanReverse64(&r, x);
216 if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
217 return 63 ^
static_cast<int>(r + 32);
219 _BitScanReverse(&r, static_cast<uint32_t>(x));
221 return 63 ^
static_cast<int>(r);
223 # define FMTQUILL_BUILTIN_CLZLL(n) detail::clzll(n) 224 #endif // FMTQUILL_MSC_VERSION && !defined(FMTQUILL_BUILTIN_CLZLL) 226 FMTQUILL_CONSTEXPR
inline void abort_fuzzing_if(
bool condition) {
227 ignore_unused(condition);
229 if (condition)
throw std::runtime_error(
"fuzzing limit reached");
233 #if defined(FMTQUILL_USE_STRING_VIEW) 234 template <
typename Char>
using std_string_view = std::basic_string_view<Char>;
242 static constexpr Char
value[
sizeof...(C)] = {C...};
244 return {
value,
sizeof...(C)};
247 #if FMTQUILL_CPLUSPLUS < 201703L 248 template <
typename Char, Char... C>
253 template <
typename To,
typename From, FMTQUILL_ENABLE_IF(sizeof(To) == sizeof(From))>
254 FMTQUILL_CONSTEXPR20
auto bit_cast(
const From& from) -> To {
255 #ifdef __cpp_lib_bit_cast 256 if (is_constant_evaluated())
return std::bit_cast<To>(from);
260 std::memcpy(static_cast<void*>(&to), &from,
sizeof(to));
264 inline auto is_big_endian() ->
bool {
267 #elif defined(__BIG_ENDIAN__) 269 #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) 270 return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;
273 char data[
sizeof(int)];
275 return bit_cast<
bytes>(1).data[0] == 0;
285 constexpr uint128_fallback(uint64_t
value = 0) : lo_(
value), hi_(0) {}
287 constexpr
auto high()
const noexcept -> uint64_t {
return hi_; }
288 constexpr
auto low()
const noexcept -> uint64_t {
return lo_; }
290 template <typename T, FMTQUILL_ENABLE_IF(std::is_integral<T>::value)>
291 constexpr
explicit operator T()
const {
292 return static_cast<T
>(lo_);
295 friend constexpr
auto operator==(
const uint128_fallback& lhs,
296 const uint128_fallback& rhs) ->
bool {
297 return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_;
299 friend constexpr
auto operator!=(
const uint128_fallback& lhs,
300 const uint128_fallback& rhs) ->
bool {
301 return !(lhs == rhs);
303 friend constexpr
auto operator>(
const uint128_fallback& lhs,
304 const uint128_fallback& rhs) ->
bool {
305 return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_;
307 friend constexpr
auto operator|(
const uint128_fallback& lhs,
308 const uint128_fallback& rhs)
309 -> uint128_fallback {
310 return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_};
312 friend constexpr
auto operator&(
const uint128_fallback& lhs,
313 const uint128_fallback& rhs)
314 -> uint128_fallback {
315 return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_};
317 friend constexpr
auto operator~(
const uint128_fallback& n)
318 -> uint128_fallback {
319 return {~n.hi_, ~n.lo_};
321 friend FMTQUILL_CONSTEXPR
auto operator+(
const uint128_fallback& lhs,
322 const uint128_fallback& rhs)
323 -> uint128_fallback {
324 auto result = uint128_fallback(lhs);
328 friend FMTQUILL_CONSTEXPR
auto operator*(
const uint128_fallback& lhs, uint32_t rhs)
329 -> uint128_fallback {
330 FMTQUILL_ASSERT(lhs.hi_ == 0,
"");
331 uint64_t hi = (lhs.lo_ >> 32) * rhs;
332 uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs;
333 uint64_t new_lo = (hi << 32) + lo;
334 return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo};
336 friend constexpr
auto operator-(
const uint128_fallback& lhs, uint64_t rhs)
337 -> uint128_fallback {
338 return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs};
340 FMTQUILL_CONSTEXPR
auto operator>>(
int shift)
const -> uint128_fallback {
341 if (shift == 64)
return {0, hi_};
342 if (shift > 64)
return uint128_fallback(0, hi_) >> (shift - 64);
343 return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)};
345 FMTQUILL_CONSTEXPR
auto operator<<(
int shift)
const -> uint128_fallback {
346 if (shift == 64)
return {lo_, 0};
347 if (shift > 64)
return uint128_fallback(lo_, 0) << (shift - 64);
348 return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)};
350 FMTQUILL_CONSTEXPR
auto operator>>=(
int shift) -> uint128_fallback& {
351 return *
this = *
this >> shift;
353 FMTQUILL_CONSTEXPR
void operator+=(uint128_fallback n) {
354 uint64_t new_lo = lo_ + n.lo_;
355 uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0);
356 FMTQUILL_ASSERT(new_hi >= hi_,
"");
360 FMTQUILL_CONSTEXPR
void operator&=(uint128_fallback n) {
365 FMTQUILL_CONSTEXPR20
auto operator+=(uint64_t n) noexcept -> uint128_fallback& {
366 if (is_constant_evaluated()) {
368 hi_ += (lo_ < n ? 1 : 0);
371 #if FMTQUILL_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__) 372 unsigned long long carry;
373 lo_ = __builtin_addcll(lo_, n, 0, &carry);
375 #elif FMTQUILL_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__) 376 unsigned long long result;
377 auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result);
380 #elif defined(_MSC_VER) && defined(_M_X64) 381 auto carry = _addcarry_u64(0, lo_, n, &lo_);
382 _addcarry_u64(carry, hi_, 0, &hi_);
385 hi_ += (lo_ < n ? 1 : 0);
391 using uint128_t = conditional_t<FMTQUILL_USE_INT128, uint128_opt, uint128_fallback>;
394 using uintptr_t = ::uintptr_t;
396 using uintptr_t = uint128_t;
401 template <
typename T> constexpr
auto max_value() -> T {
402 return (std::numeric_limits<T>::max)();
404 template <
typename T> constexpr
auto num_bits() ->
int {
405 return std::numeric_limits<T>::digits;
408 template <> constexpr
auto num_bits<int128_opt>() ->
int {
return 128; }
409 template <> constexpr
auto num_bits<uint128_opt>() ->
int {
return 128; }
410 template <> constexpr
auto num_bits<uint128_fallback>() ->
int {
return 128; }
414 template <
typename To,
typename From, FMTQUILL_ENABLE_IF(sizeof(To) >
sizeof(From))>
415 inline auto bit_cast(
const From& from) -> To {
416 constexpr
auto size =
static_cast<int>(
sizeof(From) /
sizeof(
unsigned short));
418 unsigned short value[
static_cast<unsigned>(size)];
419 } data = bit_cast<data_t>(from);
421 if (const_check(is_big_endian())) {
422 for (
int i = 0; i < size; ++i)
423 result = (result << num_bits<unsigned short>()) | data.value[i];
425 for (
int i = size - 1; i >= 0; --i)
426 result = (result << num_bits<unsigned short>()) | data.value[i];
431 template <
typename UInt>
432 FMTQUILL_CONSTEXPR20
inline auto countl_zero_fallback(UInt n) ->
int {
434 constexpr UInt msb_mask =
static_cast<UInt
>(1) << (num_bits<UInt>() - 1);
435 for (; (n & msb_mask) == 0; n <<= 1) lz++;
439 FMTQUILL_CONSTEXPR20
inline auto countl_zero(uint32_t n) ->
int {
440 #ifdef FMTQUILL_BUILTIN_CLZ 441 if (!is_constant_evaluated())
return FMTQUILL_BUILTIN_CLZ(n);
443 return countl_zero_fallback(n);
446 FMTQUILL_CONSTEXPR20
inline auto countl_zero(uint64_t n) ->
int {
447 #ifdef FMTQUILL_BUILTIN_CLZLL 448 if (!is_constant_evaluated())
return FMTQUILL_BUILTIN_CLZLL(n);
450 return countl_zero_fallback(n);
453 FMTQUILL_INLINE
void assume(
bool condition) {
455 #if FMTQUILL_HAS_BUILTIN(__builtin_assume) && !FMTQUILL_ICC_VERSION 456 __builtin_assume(condition);
457 #elif FMTQUILL_GCC_VERSION 458 if (!condition) __builtin_unreachable();
464 template <
typename OutputIt,
467 #if FMTQUILL_CLANG_VERSION >= 307 && !FMTQUILL_ICC_VERSION 468 __attribute__((no_sanitize(
"undefined")))
470 FMTQUILL_CONSTEXPR20
inline auto 471 reserve(OutputIt it,
size_t n) ->
typename OutputIt::value_type* {
472 auto& c = get_container(it);
473 size_t size = c.size();
478 template <
typename T>
482 buf.try_reserve(buf.
size() + n);
486 template <
typename Iterator>
487 constexpr
auto reserve(Iterator& it,
size_t) -> Iterator& {
491 template <
typename OutputIt>
492 using reserve_iterator =
493 remove_reference_t<decltype(reserve(std::declval<OutputIt&>(), 0))>;
495 template <
typename T,
typename OutputIt>
496 constexpr
auto to_pointer(OutputIt,
size_t) -> T* {
499 template <
typename T>
502 buf.try_reserve(buf.
size() + n);
503 auto size = buf.
size();
504 if (buf.
capacity() < size + n)
return nullptr;
505 buf.try_resize(size + n);
506 return buf.
data() + size;
509 template <
typename OutputIt,
512 inline auto base_iterator(OutputIt it,
513 typename OutputIt::container_type::value_type*)
518 template <
typename Iterator>
519 constexpr
auto base_iterator(Iterator, Iterator it) -> Iterator {
525 template <
typename OutputIt,
typename Size,
typename T>
526 FMTQUILL_CONSTEXPR
auto fill_n(OutputIt out, Size count,
const T&
value)
528 for (Size i = 0; i < count; ++i) *out++ = value;
531 template <
typename T,
typename Size>
532 FMTQUILL_CONSTEXPR20
auto fill_n(T* out, Size count,
char value) -> T* {
533 if (is_constant_evaluated())
return fill_n<T*, Size, T>(out, count, value);
534 std::memset(out, value, to_unsigned(count));
538 template <
typename OutChar,
typename InputIt,
typename OutputIt>
539 FMTQUILL_CONSTEXPR FMTQUILL_NOINLINE
auto copy_noinline(InputIt begin, InputIt end,
540 OutputIt out) -> OutputIt {
541 return copy<OutChar>(begin, end, out);
561 FMTQUILL_CONSTEXPR
inline auto utf8_decode(
const char* s, uint32_t* c,
int* e)
563 constexpr
const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
564 constexpr
const uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
565 constexpr
const int shiftc[] = {0, 18, 12, 6, 0};
566 constexpr
const int shifte[] = {0, 6, 4, 2, 0};
568 int len =
"\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4" 569 [
static_cast<unsigned char>(*s) >> 3];
573 const char* next = s + len + !len;
575 using uchar =
unsigned char;
579 *c = uint32_t(uchar(s[0]) & masks[len]) << 18;
580 *c |= uint32_t(uchar(s[1]) & 0x3f) << 12;
581 *c |= uint32_t(uchar(s[2]) & 0x3f) << 6;
582 *c |= uint32_t(uchar(s[3]) & 0x3f) << 0;
586 *e = (*c < mins[len]) << 6;
587 *e |= ((*c >> 11) == 0x1b) << 7;
588 *e |= (*c > 0x10FFFF) << 8;
589 *e |= (uchar(s[1]) & 0xc0) >> 2;
590 *e |= (uchar(s[2]) & 0xc0) >> 4;
591 *e |= uchar(s[3]) >> 6;
598 constexpr FMTQUILL_INLINE_VARIABLE uint32_t invalid_code_point = ~uint32_t();
602 template <
typename F>
603 FMTQUILL_CONSTEXPR
void for_each_codepoint(
string_view s, F f) {
604 auto decode = [f](
const char* buf_ptr,
const char* ptr) {
605 auto cp = uint32_t();
607 auto end = utf8_decode(buf_ptr, &cp, &
error);
608 bool result = f(
error ? invalid_code_point : cp,
610 return result ? (
error ? buf_ptr + 1 : end) :
nullptr;
614 const size_t block_size = 4;
615 if (s.
size() >= block_size) {
616 for (
auto end = p + s.
size() - block_size + 1; p < end;) {
621 auto num_chars_left = to_unsigned(s.
data() + s.
size() - p);
622 if (num_chars_left == 0)
return;
625 if (FMTQUILL_GCC_VERSION) num_chars_left &= 3;
626 #if defined(__GNUC__) && !defined(__clang__) 627 #pragma GCC diagnostic push 628 #pragma GCC diagnostic ignored "-Wstringop-overflow" 630 char buf[2 * block_size - 1] = {};
631 #if defined(__GNUC__) && !defined(__clang__) 632 #pragma GCC diagnostic pop 634 copy<char>(p, p + num_chars_left, buf);
635 const char* buf_ptr = buf;
637 auto end = decode(buf_ptr, p);
641 }
while (buf_ptr < buf + num_chars_left);
644 template <
typename Char>
650 FMTQUILL_CONSTEXPR
inline auto compute_width(
string_view s) ->
size_t {
651 size_t num_code_points = 0;
653 struct count_code_points {
655 FMTQUILL_CONSTEXPR
auto operator()(uint32_t cp,
string_view)
const ->
bool {
656 *count += to_unsigned(
663 (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) ||
664 (cp >= 0xac00 && cp <= 0xd7a3) ||
665 (cp >= 0xf900 && cp <= 0xfaff) ||
666 (cp >= 0xfe10 && cp <= 0xfe19) ||
667 (cp >= 0xfe30 && cp <= 0xfe6f) ||
668 (cp >= 0xff00 && cp <= 0xff60) ||
669 (cp >= 0xffe0 && cp <= 0xffe6) ||
670 (cp >= 0x20000 && cp <= 0x2fffd) ||
671 (cp >= 0x30000 && cp <= 0x3fffd) ||
673 (cp >= 0x1f300 && cp <= 0x1f64f) ||
675 (cp >= 0x1f900 && cp <= 0x1f9ff))));
680 for_each_codepoint(s, count_code_points{&num_code_points});
681 return num_code_points;
684 template <
typename Char>
686 return min_of(n, s.
size());
690 inline auto code_point_index(
string_view s,
size_t n) ->
size_t {
691 size_t result = s.
size();
692 const char* begin = s.begin();
693 for_each_codepoint(s, [begin, &n, &result](uint32_t,
string_view sv) {
698 result = to_unsigned(sv.begin() - begin);
704 template <
typename T>
struct is_integral : std::is_integral<T> {};
708 template <
typename T>
710 std::integral_constant<bool, std::numeric_limits<T>::is_signed ||
711 std::is_same<T, int128_opt>::value>;
713 template <
typename T>
715 bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value &&
716 !std::is_same<T, char>::value &&
717 !std::is_same<T, wchar_t>::value>;
719 #if defined(FMTQUILL_USE_FLOAT128) 721 #elif FMTQUILL_CLANG_VERSION >= 309 && FMTQUILL_HAS_INCLUDE(<quadmath.h>) 722 # define FMTQUILL_USE_FLOAT128 1 723 #elif FMTQUILL_GCC_VERSION && defined(_GLIBCXX_USE_FLOAT128) && \ 724 !defined(__STRICT_ANSI__) 725 # define FMTQUILL_USE_FLOAT128 1 727 # define FMTQUILL_USE_FLOAT128 0 729 #if FMTQUILL_USE_FLOAT128 735 template <
typename T>
using is_float128 = std::is_same<T, float128>;
740 template <typename T, bool = is_floating_point<T>::value>
741 struct is_fast_float : bool_constant<std::numeric_limits<T>::is_iec559 &&
742 sizeof(T) <= sizeof(double)> {};
743 template <typename T> struct is_fast_float<T, false> : std::false_type {};
745 template <typename T>
746 using is_double_double = bool_constant<std::numeric_limits<T>::digits == 106>;
748 #ifndef FMTQUILL_USE_FULL_CACHE_DRAGONBOX
749 # define FMTQUILL_USE_FULL_CACHE_DRAGONBOX 0
754 template <typename T> struct allocator {
755 using value_type = T;
757 T* allocate(size_t n) {
758 FMTQUILL_ASSERT(n <= max_value<size_t>() / sizeof(T), "");
759 T* p = static_cast<T*>(malloc(n * sizeof(T)));
760 if (!p) FMTQUILL_THROW(std::bad_alloc());
764 void deallocate(T* p, size_t) { free(p); }
769 FMTQUILL_BEGIN_EXPORT
773 enum { inline_buffer_size = 500 };
788 template <typename T, size_t SIZE = inline_buffer_size,
789 typename Allocator = detail::allocator<T>>
790 class basic_memory_buffer : public detail::buffer<T> {
795 FMTQUILL_NO_UNIQUE_ADDRESS Allocator alloc_;
798 FMTQUILL_CONSTEXPR20 void deallocate() {
799 T* data = this->data();
800 if (data != store_) alloc_.deallocate(data, this->capacity());
803 static FMTQUILL_CONSTEXPR20 void grow(detail::buffer<T>& buf, size_t size) {
804 detail::abort_fuzzing_if(size > 5000);
806 const size_t max_size =
807 std::allocator_traits<Allocator>::max_size(
self.alloc_);
808 size_t old_capacity = buf.capacity();
809 size_t new_capacity = old_capacity + old_capacity / 2;
810 if (size > new_capacity)
812 else if (new_capacity > max_size)
813 new_capacity = max_of(size, max_size);
814 T* old_data = buf.data();
815 T* new_data =
self.alloc_.allocate(new_capacity);
817 detail::assume(buf.size() <= new_capacity);
819 memcpy(new_data, old_data, buf.size() *
sizeof(T));
820 self.set(new_data, new_capacity);
824 if (old_data !=
self.store_)
self.alloc_.deallocate(old_data, old_capacity);
828 using value_type = T;
829 using const_reference =
const T&;
832 const Allocator& alloc = Allocator())
834 this->
set(store_, SIZE);
835 if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T());
837 FMTQUILL_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); }
841 FMTQUILL_CONSTEXPR20
void move(basic_memory_buffer& other) {
842 alloc_ = std::move(other.alloc_);
843 T* data = other.
data();
844 size_t size = other.
size(), capacity = other.
capacity();
845 if (data == other.store_) {
846 this->
set(store_, capacity);
847 detail::copy<T>(other.store_, other.store_ + size, store_);
849 this->
set(data, capacity);
852 other.
set(other.store_, 0);
867 auto operator=(basic_memory_buffer&& other) noexcept -> basic_memory_buffer& {
868 FMTQUILL_ASSERT(
this != &other,
"");
875 auto get_allocator()
const -> Allocator {
return alloc_; }
879 FMTQUILL_CONSTEXPR
void resize(
size_t count) { this->try_resize(count); }
882 void reserve(
size_t new_capacity) { this->try_reserve(new_capacity); }
885 template <
typename ContiguousRange>
886 FMTQUILL_CONSTEXPR20
void append(
const ContiguousRange& range) {
887 append(range.data(), range.data() + range.size());
893 template <
size_t SIZE>
896 auto size = buf.
size();
897 detail::assume(size < std::string().max_size());
898 return {buf.
data(), size};
911 inline writer(FILE* f) : buf_(
nullptr), file_(f) {}
916 template <
typename... T>
void print(format_string<T...> fmt, T&&... args) {
918 fmtquill::format_to(
appender(*buf_), fmt, std::forward<T>(args)...);
920 fmtquill::print(file_, fmt, std::forward<T>(args)...);
932 inline operator writer() {
return buf_; }
933 inline std::string& str() {
return str_; }
936 template <
typename T,
size_t SIZE,
typename Allocator>
941 FMTQUILL_PRAGMA_CLANG(diagnostic ignored
"-Wweak-vtables")
943 class FMTQUILL_SO_VISIBILITY("default") format_error :
public std::runtime_error {
946 using std::runtime_error::runtime_error;
953 FMTQUILL_API
auto write_console(
int fd,
string_view text) -> bool;
960 detail::copy<Char, const Char*, Char*>(
static_cast<const Char*
>(s), s + N,
967 FMTQUILL_EXPORT
template <
typename Char,
size_t N>
968 constexpr
auto compile_string_to_view(
const Char (&s)[N])
974 FMTQUILL_EXPORT
template <
typename Char>
982 template <typename T, FMTQUILL_ENABLE_IF(is_signed<T>::value)>
983 constexpr
auto is_negative(T
value) ->
bool {
986 template <typename T, FMTQUILL_ENABLE_IF(!is_signed<T>::value)>
987 constexpr
auto is_negative(T) ->
bool {
993 template <
typename T>
994 using uint32_or_64_or_128_t =
995 conditional_t<num_bits<T>() <= 32 && !FMTQUILL_REDUCE_INT_INSTANTIATIONS,
997 conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>;
998 template <
typename T>
999 using uint64_or_128_t = conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>;
1001 #define FMTQUILL_POWERS_OF_10(factor) \ 1002 factor * 10, (factor) * 100, (factor) * 1000, (factor) * 10000, \ 1003 (factor) * 100000, (factor) * 1000000, (factor) * 10000000, \ 1004 (factor) * 100000000, (factor) * 1000000000 1008 inline auto digits2(
size_t value) ->
const char* {
1011 alignas(2)
static const char data[] =
1012 "0001020304050607080910111213141516171819" 1013 "2021222324252627282930313233343536373839" 1014 "4041424344454647484950515253545556575859" 1015 "6061626364656667686970717273747576777879" 1016 "8081828384858687888990919293949596979899";
1017 return &data[value * 2];
1020 template <
typename Char> constexpr
auto getsign(sign s) -> Char {
1021 return static_cast<char>(((
' ' << 24) | (
'+' << 16) | (
'-' << 8)) >>
1022 (
static_cast<int>(s) * 8));
1025 template <
typename T> FMTQUILL_CONSTEXPR
auto count_digits_fallback(T n) ->
int {
1031 if (n < 10)
return count;
1032 if (n < 100)
return count + 1;
1033 if (n < 1000)
return count + 2;
1034 if (n < 10000)
return count + 3;
1039 #if FMTQUILL_USE_INT128 1040 FMTQUILL_CONSTEXPR
inline auto count_digits(uint128_opt n) ->
int {
1041 return count_digits_fallback(n);
1045 #ifdef FMTQUILL_BUILTIN_CLZLL 1048 inline auto do_count_digits(uint64_t n) ->
int {
1053 static constexpr uint8_t bsr2log10[] = {
1054 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
1055 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
1056 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
1057 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20};
1058 auto t = bsr2log10[FMTQUILL_BUILTIN_CLZLL(n | 1) ^ 63];
1059 static constexpr
const uint64_t zero_or_powers_of_10[] = {
1060 0, 0, FMTQUILL_POWERS_OF_10(1U), FMTQUILL_POWERS_OF_10(1000000000ULL),
1061 10000000000000000000ULL};
1062 return t - (n < zero_or_powers_of_10[t]);
1068 FMTQUILL_CONSTEXPR20
inline auto count_digits(uint64_t n) ->
int {
1069 #ifdef FMTQUILL_BUILTIN_CLZLL 1070 if (!is_constant_evaluated() && !FMTQUILL_OPTIMIZE_SIZE)
return do_count_digits(n);
1072 return count_digits_fallback(n);
1076 template <
int BITS,
typename UInt>
1077 FMTQUILL_CONSTEXPR
auto count_digits(UInt n) ->
int {
1078 #ifdef FMTQUILL_BUILTIN_CLZ 1079 if (!is_constant_evaluated() && num_bits<UInt>() == 32)
1080 return (FMTQUILL_BUILTIN_CLZ(static_cast<uint32_t>(n) | 1) ^ 31) / BITS + 1;
1087 }
while ((m >>= BITS) != 0);
1092 #ifdef FMTQUILL_BUILTIN_CLZ 1095 FMTQUILL_INLINE
auto do_count_digits(uint32_t n) ->
int {
1098 # define FMTQUILL_INC(T) (((sizeof(#T) - 1ull) << 32) - T) 1099 static constexpr uint64_t table[] = {
1100 FMTQUILL_INC(0), FMTQUILL_INC(0), FMTQUILL_INC(0),
1101 FMTQUILL_INC(10), FMTQUILL_INC(10), FMTQUILL_INC(10),
1102 FMTQUILL_INC(100), FMTQUILL_INC(100), FMTQUILL_INC(100),
1103 FMTQUILL_INC(1000), FMTQUILL_INC(1000), FMTQUILL_INC(1000),
1104 FMTQUILL_INC(10000), FMTQUILL_INC(10000), FMTQUILL_INC(10000),
1105 FMTQUILL_INC(100000), FMTQUILL_INC(100000), FMTQUILL_INC(100000),
1106 FMTQUILL_INC(1000000), FMTQUILL_INC(1000000), FMTQUILL_INC(1000000),
1107 FMTQUILL_INC(10000000), FMTQUILL_INC(10000000), FMTQUILL_INC(10000000),
1108 FMTQUILL_INC(100000000), FMTQUILL_INC(100000000), FMTQUILL_INC(100000000),
1109 FMTQUILL_INC(1000000000), FMTQUILL_INC(1000000000), FMTQUILL_INC(1000000000),
1110 FMTQUILL_INC(1000000000), FMTQUILL_INC(1000000000)
1112 auto inc = table[FMTQUILL_BUILTIN_CLZ(n | 1) ^ 31];
1113 return static_cast<int>((n + inc) >> 32);
1118 FMTQUILL_CONSTEXPR20
inline auto count_digits(uint32_t n) ->
int {
1119 #ifdef FMTQUILL_BUILTIN_CLZ 1120 if (!is_constant_evaluated() && !FMTQUILL_OPTIMIZE_SIZE)
return do_count_digits(n);
1122 return count_digits_fallback(n);
1125 template <
typename Int> constexpr
auto digits10() noexcept ->
int {
1126 return std::numeric_limits<Int>::digits10;
1128 template <> constexpr
auto digits10<int128_opt>() noexcept ->
int {
return 38; }
1129 template <> constexpr
auto digits10<uint128_t>() noexcept ->
int {
return 38; }
1132 std::string grouping;
1136 template <
typename Char>
1138 template <
typename Char>
1140 auto result = thousands_sep_impl<char>(loc);
1141 return {result.grouping, Char(result.thousands_sep)};
1145 return thousands_sep_impl<wchar_t>(loc);
1148 template <
typename Char>
1149 FMTQUILL_API
auto decimal_point_impl(
locale_ref loc) -> Char;
1150 template <
typename Char>
inline auto decimal_point(
locale_ref loc) -> Char {
1151 return Char(decimal_point_impl<char>(loc));
1153 template <>
inline auto decimal_point(
locale_ref loc) ->
wchar_t {
1154 return decimal_point_impl<wchar_t>(loc);
1157 #ifndef FMTQUILL_HEADER_ONLY 1158 FMTQUILL_BEGIN_EXPORT
1159 extern template FMTQUILL_API
auto thousands_sep_impl<char>(
locale_ref)
1161 extern template FMTQUILL_API
auto thousands_sep_impl<wchar_t>(
locale_ref)
1163 extern template FMTQUILL_API
auto decimal_point_impl(
locale_ref) -> char;
1164 extern template FMTQUILL_API
auto decimal_point_impl(
locale_ref) -> wchar_t;
1166 #endif // FMTQUILL_HEADER_ONLY 1169 template <
typename Char>
auto equal2(
const Char* lhs,
const char* rhs) ->
bool {
1170 return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]);
1172 inline auto equal2(
const char* lhs,
const char* rhs) ->
bool {
1173 return memcmp(lhs, rhs, 2) == 0;
1177 template <
typename Char>
1178 FMTQUILL_CONSTEXPR20 FMTQUILL_INLINE
void write2digits(Char* out,
size_t value) {
1179 if (!is_constant_evaluated() && std::is_same<Char, char>::value &&
1180 !FMTQUILL_OPTIMIZE_SIZE) {
1181 memcpy(out, digits2(value), 2);
1184 *out++ =
static_cast<Char
>(
'0' + value / 10);
1185 *out =
static_cast<Char
>(
'0' + value % 10);
1190 template <
typename Char,
typename UInt>
1191 FMTQUILL_CONSTEXPR20
auto do_format_decimal(Char* out, UInt value,
int size)
1193 FMTQUILL_ASSERT(size >= count_digits(value),
"invalid digit count");
1194 unsigned n = to_unsigned(size);
1195 while (value >= 100) {
1200 write2digits(out + n, static_cast<unsigned>(value % 100));
1205 write2digits(out + n, static_cast<unsigned>(value));
1207 out[--n] =
static_cast<Char
>(
'0' + value);
1212 template <
typename Char,
typename UInt>
1213 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
auto format_decimal(Char* out, UInt value,
1214 int num_digits) -> Char* {
1215 do_format_decimal(out, value, num_digits);
1216 return out + num_digits;
1219 template <
typename Char,
typename UInt,
typename OutputIt,
1220 FMTQUILL_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)>
1221 FMTQUILL_CONSTEXPR
auto format_decimal(OutputIt out, UInt value,
int num_digits)
1223 if (
auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
1224 do_format_decimal(ptr, value, num_digits);
1228 char buffer[digits10<UInt>() + 1];
1229 if (is_constant_evaluated()) fill_n(
buffer,
sizeof(
buffer),
'\0');
1230 do_format_decimal(
buffer, value, num_digits);
1231 return copy_noinline<Char>(
buffer, buffer + num_digits, out);
1234 template <
typename Char,
typename UInt>
1235 FMTQUILL_CONSTEXPR
auto do_format_base2e(
int base_bits, Char* out, UInt value,
1236 int size,
bool upper =
false) -> Char* {
1239 const char* digits = upper ?
"0123456789ABCDEF" :
"0123456789abcdef";
1240 unsigned digit =
static_cast<unsigned>(value & ((1 << base_bits) - 1));
1241 *--out =
static_cast<Char
>(base_bits < 4 ? static_cast<char>(
'0' + digit)
1243 }
while ((value >>= base_bits) != 0);
1248 template <
typename Char,
typename UInt>
1249 FMTQUILL_CONSTEXPR
auto format_base2e(
int base_bits, Char* out, UInt value,
1250 int num_digits,
bool upper =
false) -> Char* {
1251 do_format_base2e(base_bits, out, value, num_digits, upper);
1252 return out + num_digits;
1255 template <
typename Char,
typename OutputIt,
typename UInt,
1257 FMTQUILL_CONSTEXPR
inline auto format_base2e(
int base_bits, OutputIt out, UInt value,
1258 int num_digits,
bool upper =
false)
1260 if (
auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
1261 format_base2e(base_bits, ptr, value, num_digits, upper);
1265 char buffer[num_bits<UInt>()];
1266 if (is_constant_evaluated()) fill_n(
buffer,
sizeof(
buffer),
'\0');
1267 format_base2e(base_bits,
buffer, value, num_digits, upper);
1268 return detail::copy_noinline<Char>(
buffer, buffer + num_digits, out);
1279 return {&buffer_[0], size()};
1281 inline auto size()
const ->
size_t {
return buffer_.
size() - 1; }
1282 inline auto c_str()
const ->
const wchar_t* {
return &buffer_[0]; }
1283 inline auto str()
const -> std::wstring {
return {&buffer_[0], size()}; }
1286 enum class to_utf8_error_policy { abort, replace };
1289 template <
typename WChar,
typename Buffer = memory_buffer>
class to_utf8 {
1296 to_utf8_error_policy policy = to_utf8_error_policy::abort) {
1297 static_assert(
sizeof(WChar) == 2 ||
sizeof(WChar) == 4,
1298 "Expect utf16 or utf32");
1299 if (!convert(s, policy))
1300 FMTQUILL_THROW(std::runtime_error(
sizeof(WChar) == 2 ?
"invalid utf16" 1301 :
"invalid utf32"));
1304 auto size()
const ->
size_t {
return buffer_.size() - 1; }
1305 auto c_str()
const ->
const char* {
return &buffer_[0]; }
1306 auto str()
const -> std::string {
return std::string(&buffer_[0], size()); }
1312 to_utf8_error_policy policy = to_utf8_error_policy::abort)
1314 if (!convert(buffer_, s, policy))
return false;
1315 buffer_.push_back(0);
1319 to_utf8_error_policy policy = to_utf8_error_policy::abort)
1321 for (
auto p = s.begin(); p != s.end(); ++p) {
1322 uint32_t c =
static_cast<uint32_t
>(*p);
1323 if (
sizeof(WChar) == 2 && c >= 0xd800 && c <= 0xdfff) {
1326 if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) {
1327 if (policy == to_utf8_error_policy::abort)
return false;
1332 c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;
1336 buf.push_back(static_cast<char>(c));
1337 }
else if (c < 0x800) {
1338 buf.push_back(static_cast<char>(0xc0 | (c >> 6)));
1339 buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
1340 }
else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
1341 buf.push_back(static_cast<char>(0xe0 | (c >> 12)));
1342 buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
1343 buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
1344 }
else if (c >= 0x10000 && c <= 0x10ffff) {
1345 buf.push_back(static_cast<char>(0xf0 | (c >> 18)));
1346 buf.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
1347 buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
1348 buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
1359 #if FMTQUILL_USE_INT128 1360 auto p =
static_cast<uint128_opt
>(x) * static_cast<uint128_opt>(y);
1361 return {
static_cast<uint64_t
>(p >> 64), static_cast<uint64_t>(p)};
1362 #elif defined(_MSC_VER) && defined(_M_X64) 1363 auto hi = uint64_t();
1364 auto lo = _umul128(x, y, &hi);
1367 const uint64_t mask =
static_cast<uint64_t
>(max_value<uint32_t>());
1369 uint64_t a = x >> 32;
1370 uint64_t b = x & mask;
1371 uint64_t c = y >> 32;
1372 uint64_t d = y & mask;
1374 uint64_t ac = a * c;
1375 uint64_t bc = b * c;
1376 uint64_t ad = a * d;
1377 uint64_t bd = b * d;
1379 uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask);
1381 return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32),
1382 (intermediate << 32) + (bd & mask)};
1386 namespace dragonbox {
1389 inline auto floor_log10_pow2(
int e) noexcept ->
int {
1390 FMTQUILL_ASSERT(e <= 2620 && e >= -2620,
"too large exponent");
1391 static_assert((-1 >> 1) == -1,
"right shift is not arithmetic");
1392 return (e * 315653) >> 20;
1395 inline auto floor_log2_pow10(
int e) noexcept ->
int {
1396 FMTQUILL_ASSERT(e <= 1233 && e >= -1233,
"too large exponent");
1397 return (e * 1741647) >> 19;
1401 inline auto umul128_upper64(uint64_t x, uint64_t y) noexcept -> uint64_t {
1402 #if FMTQUILL_USE_INT128 1403 auto p =
static_cast<uint128_opt
>(x) * static_cast<uint128_opt>(y);
1404 return static_cast<uint64_t
>(p >> 64);
1405 #elif defined(_MSC_VER) && defined(_M_X64) 1406 return __umulh(x, y);
1408 return umul128(x, y).high();
1417 r += umul128_upper64(x, y.low());
1427 using carrier_uint = uint32_t;
1428 static const int exponent_bits = 8;
1429 static const int kappa = 1;
1430 static const int big_divisor = 100;
1431 static const int small_divisor = 10;
1432 static const int min_k = -31;
1433 static const int max_k = 46;
1434 static const int shorter_interval_tie_lower_threshold = -35;
1435 static const int shorter_interval_tie_upper_threshold = -35;
1439 using carrier_uint = uint64_t;
1440 static const int exponent_bits = 11;
1441 static const int kappa = 2;
1442 static const int big_divisor = 1000;
1443 static const int small_divisor = 100;
1444 static const int min_k = -292;
1445 static const int max_k = 341;
1446 static const int shorter_interval_tie_lower_threshold = -77;
1447 static const int shorter_interval_tie_upper_threshold = -77;
1451 template <
typename T>
1452 struct float_info<T, enable_if_t<std::numeric_limits<T>::digits == 64 ||
1453 std::numeric_limits<T>::digits == 113 ||
1455 using carrier_uint = detail::uint128_t;
1456 static const int exponent_bits = 15;
1460 template <
typename T>
1462 using carrier_uint = detail::uint128_t;
1467 significand_type significand;
1471 template <
typename T> FMTQUILL_API
auto to_decimal(T x) noexcept ->
decimal_fp<T>;
1475 template <
typename Float> constexpr
auto has_implicit_bit() ->
bool {
1477 return std::numeric_limits<Float>::digits != 64;
1482 template <
typename Float> constexpr
auto num_significand_bits() ->
int {
1484 return is_float128<Float>() ? 112
1485 : (std::numeric_limits<Float>::digits -
1486 (has_implicit_bit<Float>() ? 1 : 0));
1489 template <
typename Float>
1490 constexpr
auto exponent_mask() ->
1494 << num_significand_bits<Float>();
1496 template <
typename Float> constexpr
auto exponent_bias() ->
int {
1498 return is_float128<Float>() ? 16383
1499 : std::numeric_limits<Float>::max_exponent - 1;
1503 template <
typename Char,
typename OutputIt>
1504 FMTQUILL_CONSTEXPR
auto write_exponent(
int exp, OutputIt out) -> OutputIt {
1505 FMTQUILL_ASSERT(-10000 < exp && exp < 10000,
"exponent out of range");
1507 *out++ =
static_cast<Char
>(
'-');
1510 *out++ =
static_cast<Char
>(
'+');
1512 auto uexp =
static_cast<uint32_t
>(exp);
1513 if (is_constant_evaluated()) {
1514 if (uexp < 10) *out++ =
'0';
1515 return format_decimal<Char>(out, uexp, count_digits(uexp));
1518 const char* top = digits2(uexp / 100);
1519 if (uexp >= 1000u) *out++ =
static_cast<Char
>(top[0]);
1520 *out++ =
static_cast<Char
>(top[1]);
1523 const char* d = digits2(uexp);
1524 *out++ =
static_cast<Char
>(d[0]);
1525 *out++ =
static_cast<Char
>(d[1]);
1534 static constexpr
const int num_significand_bits =
1535 static_cast<int>(
sizeof(F) * num_bits<unsigned char>());
1537 constexpr
basic_fp() : f(0), e(0) {}
1538 constexpr basic_fp(uint64_t f_val,
int e_val) : f(f_val), e(e_val) {}
1541 template <
typename Float> FMTQUILL_CONSTEXPR basic_fp(Float n) { assign(n); }
1544 template <typename Float, FMTQUILL_ENABLE_IF(!is_double_double<Float>::value)>
1545 FMTQUILL_CONSTEXPR
auto assign(Float n) ->
bool {
1546 static_assert(std::numeric_limits<Float>::digits <= 113,
"unsupported FP");
1549 const auto num_float_significand_bits =
1550 detail::num_significand_bits<Float>();
1551 const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
1552 const auto significand_mask = implicit_bit - 1;
1553 auto u = bit_cast<carrier_uint>(n);
1554 f =
static_cast<F
>(u & significand_mask);
1555 auto biased_e =
static_cast<int>((u & exponent_mask<Float>()) >>
1556 num_float_significand_bits);
1559 auto is_predecessor_closer = f == 0 && biased_e > 1;
1562 else if (has_implicit_bit<Float>())
1563 f += static_cast<F>(implicit_bit);
1564 e = biased_e - exponent_bias<Float>() - num_float_significand_bits;
1565 if (!has_implicit_bit<Float>()) ++e;
1566 return is_predecessor_closer;
1569 template <typename Float, FMTQUILL_ENABLE_IF(is_double_double<Float>::value)>
1570 FMTQUILL_CONSTEXPR
auto assign(Float n) ->
bool {
1571 static_assert(std::numeric_limits<double>::is_iec559,
"unsupported FP");
1572 return assign(static_cast<double>(n));
1579 template <
int SHIFT = 0,
typename F>
1582 const auto implicit_bit = F(1) << num_significand_bits<double>();
1583 const auto shifted_implicit_bit = implicit_bit << SHIFT;
1584 while ((value.f & shifted_implicit_bit) == 0) {
1590 num_significand_bits<double>() - SHIFT - 1;
1597 FMTQUILL_CONSTEXPR
inline auto multiply(uint64_t lhs, uint64_t rhs) -> uint64_t {
1598 #if FMTQUILL_USE_INT128 1599 auto product =
static_cast<__uint128_t
>(lhs) * rhs;
1600 auto f =
static_cast<uint64_t
>(product >> 64);
1601 return (static_cast<uint64_t>(product) & (1ULL << 63)) != 0 ? f + 1 : f;
1604 uint64_t mask = (1ULL << 32) - 1;
1605 uint64_t a = lhs >> 32, b = lhs & mask;
1606 uint64_t c = rhs >> 32, d = rhs & mask;
1607 uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
1609 uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
1610 return ac + (ad >> 32) + (bc >> 32) + (mid >> 32);
1614 FMTQUILL_CONSTEXPR
inline auto operator*(
fp x,
fp y) ->
fp {
1615 return {multiply(x.f, y.f), x.e + y.e + 64};
1618 template <
typename T,
bool doublish = num_bits<T>() == num_bits<
double>()>
1619 using convert_float_result =
1620 conditional_t<std::is_same<T, float>::value || doublish, double, T>;
1622 template <
typename T>
1623 constexpr
auto convert_float(T value) -> convert_float_result<T> {
1624 return static_cast<convert_float_result<T>
>(value);
1627 template <
typename Char,
typename OutputIt>
1628 FMTQUILL_CONSTEXPR FMTQUILL_NOINLINE
auto fill(OutputIt it,
size_t n,
1630 auto fill_size = specs.fill_size();
1631 if (fill_size == 1)
return detail::fill_n(it, n, specs.fill_unit<Char>());
1632 if (
const Char* data = specs.fill<Char>()) {
1633 for (
size_t i = 0; i < n; ++i) it = copy<Char>(data, data + fill_size, it);
1641 template <
typename Char, align default_align = align::left,
typename OutputIt,
1643 FMTQUILL_CONSTEXPR
auto write_padded(OutputIt out,
const format_specs& specs,
1644 size_t size,
size_t width, F&& f) -> OutputIt {
1645 static_assert(default_align == align::left || default_align == align::right,
1647 unsigned spec_width = to_unsigned(specs.width);
1648 size_t padding = spec_width > width ? spec_width - width : 0;
1652 default_align == align::left ?
"\x1f\x1f\x00\x01" :
"\x00\x1f\x00\x01";
1653 size_t left_padding = padding >> shifts[
static_cast<int>(specs.align())];
1654 size_t right_padding = padding - left_padding;
1655 auto it = reserve(out, size + padding * specs.fill_size());
1656 if (left_padding != 0) it = fill<Char>(it, left_padding, specs);
1658 if (right_padding != 0) it = fill<Char>(it, right_padding, specs);
1659 return base_iterator(out, it);
1662 template <
typename Char, align default_align = align::left,
typename OutputIt,
1664 constexpr
auto write_padded(OutputIt out,
const format_specs& specs,
1665 size_t size, F&& f) -> OutputIt {
1666 return write_padded<Char, default_align>(out, specs, size, size, f);
1669 template <
typename Char, align default_align = align::left,
typename OutputIt>
1672 return write_padded<Char, default_align>(
1673 out, specs, bytes.
size(), [bytes](reserve_iterator<OutputIt> it) {
1674 const char* data = bytes.
data();
1675 return copy<Char>(data, data + bytes.
size(), it);
1679 template <
typename Char,
typename OutputIt,
typename UIntPtr>
1680 auto write_ptr(OutputIt out, UIntPtr value,
const format_specs* specs)
1682 int num_digits = count_digits<4>(value);
1683 auto size = to_unsigned(num_digits) + size_t(2);
1684 auto write = [=](reserve_iterator<OutputIt> it) {
1685 *it++ =
static_cast<Char
>(
'0');
1686 *it++ =
static_cast<Char
>(
'x');
1687 return format_base2e<Char>(4, it, value, num_digits);
1689 return specs ? write_padded<Char, align::right>(out, *specs, size, write)
1690 : base_iterator(out, write(reserve(out, size)));
1694 FMTQUILL_API
auto is_printable(uint32_t cp) -> bool;
1696 inline auto needs_escape(uint32_t cp) ->
bool {
1697 if (cp < 0x20 || cp == 0x7f || cp ==
'"' || cp ==
'\\')
return true;
1698 if (const_check(FMTQUILL_OPTIMIZE_SIZE > 1))
return false;
1699 return !is_printable(cp);
1708 template <
typename Char>
1709 auto find_escape(
const Char* begin,
const Char* end)
1711 for (; begin != end; ++begin) {
1712 uint32_t cp =
static_cast<unsigned_char<Char>
>(*begin);
1713 if (const_check(
sizeof(Char) == 1) && cp >= 0x80)
continue;
1714 if (needs_escape(cp))
return {begin, begin + 1, cp};
1716 return {begin,
nullptr, 0};
1719 inline auto find_escape(
const char* begin,
const char* end)
1721 if (const_check(!use_utf8))
return find_escape<char>(begin, end);
1723 for_each_codepoint(
string_view(begin, to_unsigned(end - begin)),
1725 if (needs_escape(cp)) {
1726 result = {sv.begin(), sv.end(), cp};
1734 template <
size_t w
idth,
typename Char,
typename OutputIt>
1735 auto write_codepoint(OutputIt out,
char prefix, uint32_t cp) -> OutputIt {
1736 *out++ =
static_cast<Char
>(
'\\');
1737 *out++ =
static_cast<Char
>(prefix);
1739 fill_n(buf, width, static_cast<Char>(
'0'));
1740 format_base2e(4, buf, cp, width);
1741 return copy<Char>(buf, buf + width, out);
1744 template <
typename OutputIt,
typename Char>
1747 auto c =
static_cast<Char
>(escape.cp);
1748 switch (escape.cp) {
1750 *out++ =
static_cast<Char
>(
'\\');
1751 c =
static_cast<Char
>(
'n');
1754 *out++ =
static_cast<Char
>(
'\\');
1755 c =
static_cast<Char
>(
'r');
1758 *out++ =
static_cast<Char
>(
'\\');
1759 c =
static_cast<Char
>(
't');
1761 case '"': FMTQUILL_FALLTHROUGH;
1762 case '\'': FMTQUILL_FALLTHROUGH;
1763 case '\\': *out++ =
static_cast<Char
>(
'\\');
break;
1765 if (escape.cp < 0x100)
return write_codepoint<2, Char>(out,
'x', escape.cp);
1766 if (escape.cp < 0x10000)
1767 return write_codepoint<4, Char>(out,
'u', escape.cp);
1768 if (escape.cp < 0x110000)
1769 return write_codepoint<8, Char>(out,
'U', escape.cp);
1771 escape.begin, to_unsigned(escape.end - escape.begin))) {
1772 out = write_codepoint<2, Char>(out,
'x',
1773 static_cast<uint32_t
>(escape_char) & 0xFF);
1781 template <
typename Char,
typename OutputIt>
1784 *out++ =
static_cast<Char
>(
'"');
1785 auto begin = str.begin(), end = str.end();
1787 auto escape = find_escape(begin, end);
1788 out = copy<Char>(begin, escape.begin, out);
1791 out = write_escaped_cp<OutputIt, Char>(out, escape);
1792 }
while (begin != end);
1793 *out++ =
static_cast<Char
>(
'"');
1797 template <
typename Char,
typename OutputIt>
1798 auto write_escaped_char(OutputIt out, Char v) -> OutputIt {
1799 Char v_array[1] = {v};
1800 *out++ =
static_cast<Char
>(
'\'');
1801 if ((needs_escape(static_cast<uint32_t>(v)) && v != static_cast<Char>(
'"')) ||
1802 v ==
static_cast<Char
>(
'\'')) {
1803 out = write_escaped_cp(out,
1805 static_cast<uint32_t
>(v)});
1809 *out++ =
static_cast<Char
>(
'\'');
1813 template <
typename Char,
typename OutputIt>
1814 FMTQUILL_CONSTEXPR
auto write_char(OutputIt out, Char value,
1816 bool is_debug = specs.type() == presentation_type::debug;
1817 return write_padded<Char>(out, specs, 1, [=](reserve_iterator<OutputIt> it) {
1818 if (is_debug)
return write_escaped_char(it, value);
1823 template <
typename Char,
typename OutputIt>
1824 FMTQUILL_CONSTEXPR
auto write(OutputIt out, Char value,
const format_specs& specs,
1827 using unsigned_type =
1828 conditional_t<std::is_same<Char, char>::value,
unsigned char,
unsigned>;
1829 return check_char_specs(specs)
1830 ? write_char<Char>(out, value, specs)
1831 : write<Char>(out, static_cast<unsigned_type>(value), specs, loc);
1836 std::string grouping_;
1837 std::basic_string<Char> thousands_sep_;
1840 std::string::const_iterator group;
1843 auto initial_state()
const -> next_state {
return {grouping_.begin(), 0}; }
1846 auto next(next_state& state)
const ->
int {
1847 if (thousands_sep_.empty())
return max_value<int>();
1848 if (state.group == grouping_.end())
return state.pos += grouping_.back();
1849 if (*state.group <= 0 || *state.group == max_value<char>())
1850 return max_value<int>();
1851 state.pos += *state.group++;
1856 template <
typename Locale,
1857 FMTQUILL_ENABLE_IF(std::is_same<Locale, locale_ref>::value)>
1859 if (!localized)
return;
1860 auto sep = thousands_sep<Char>(loc);
1861 grouping_ = sep.grouping;
1862 if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep);
1864 digit_grouping(std::string grouping, std::basic_string<Char> sep)
1865 : grouping_(std::move(grouping)), thousands_sep_(std::move(sep)) {}
1867 auto has_separator()
const ->
bool {
return !thousands_sep_.empty(); }
1869 auto count_separators(
int num_digits)
const ->
int {
1871 auto state = initial_state();
1872 while (num_digits > next(state)) ++count;
1877 template <
typename Out,
typename C>
1879 auto num_digits =
static_cast<int>(digits.
size());
1881 separators.push_back(0);
1882 auto state = initial_state();
1883 while (
int i = next(state)) {
1884 if (i >= num_digits)
break;
1885 separators.push_back(i);
1887 for (
int i = 0, sep_index = static_cast<int>(separators.size() - 1);
1888 i < num_digits; ++i) {
1889 if (num_digits - i == separators[sep_index]) {
1890 out = copy<Char>(thousands_sep_.data(),
1891 thousands_sep_.data() + thousands_sep_.size(), out);
1894 *out++ =
static_cast<Char
>(digits[to_unsigned(i)]);
1900 FMTQUILL_CONSTEXPR
inline void prefix_append(
unsigned& prefix,
unsigned value) {
1901 prefix |= prefix != 0 ? value << 8 : value;
1902 prefix += (1u + (value > 0xff ? 1 : 0)) << 24;
1906 template <
typename OutputIt,
typename UInt,
typename Char>
1907 auto write_int(OutputIt out, UInt value,
unsigned prefix,
1910 static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value,
"");
1913 switch (specs.type()) {
1914 default: FMTQUILL_ASSERT(
false,
""); FMTQUILL_FALLTHROUGH;
1915 case presentation_type::none:
1916 case presentation_type::dec:
1917 num_digits = count_digits(value);
1920 case presentation_type::hex:
1922 prefix_append(prefix,
unsigned(specs.upper() ?
'X' :
'x') << 8 |
'0');
1923 num_digits = count_digits<4>(value);
1924 format_base2e<char>(4,
appender(
buffer), value, num_digits, specs.upper());
1926 case presentation_type::oct:
1927 num_digits = count_digits<3>(value);
1930 if (specs.alt() && specs.precision <= num_digits && value != 0)
1931 prefix_append(prefix,
'0');
1934 case presentation_type::bin:
1936 prefix_append(prefix,
unsigned(specs.upper() ?
'B' :
'b') << 8 |
'0');
1937 num_digits = count_digits<1>(value);
1940 case presentation_type::chr:
1941 return write_char<Char>(out,
static_cast<Char
>(value), specs);
1944 unsigned size = (prefix != 0 ? prefix >> 24 : 0) + to_unsigned(num_digits) +
1945 to_unsigned(grouping.count_separators(num_digits));
1946 return write_padded<Char, align::right>(
1947 out, specs, size, size, [&](reserve_iterator<OutputIt> it) {
1948 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
1949 *it++ = static_cast<Char>(p & 0xff);
1954 #if FMTQUILL_USE_LOCALE 1959 template <
typename OutputIt>
1970 template <
typename T>
1971 FMTQUILL_CONSTEXPR
auto make_write_int_arg(T value, sign s)
1974 auto abs_value =
static_cast<uint32_or_64_or_128_t<T>
>(value);
1975 if (is_negative(value)) {
1976 prefix = 0x01000000 |
'-';
1977 abs_value = 0 - abs_value;
1979 constexpr
const unsigned prefixes[4] = {0, 0, 0x1000000u |
'+',
1981 prefix = prefixes[
static_cast<int>(s)];
1983 return {abs_value, prefix};
1989 std::basic_string<Char> sep;
1990 std::string grouping;
1991 std::basic_string<Char> decimal_point;
1993 template <typename T, FMTQUILL_ENABLE_IF(is_integer<T>::value)>
1994 auto operator()(T value) ->
bool {
1995 auto arg = make_write_int_arg(value, specs.sign());
1996 write_int(out,
static_cast<uint64_or_128_t<T>
>(arg.abs_value), arg.prefix,
2001 template <typename T, FMTQUILL_ENABLE_IF(!is_integer<T>::value)>
2002 auto operator()(T) ->
bool {
2012 FMTQUILL_CONSTEXPR
size_padding(
int num_digits,
unsigned prefix,
2014 : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) {
2015 if (specs.align() == align::numeric) {
2016 auto width = to_unsigned(specs.width);
2018 padding = width - size;
2021 }
else if (specs.precision > num_digits) {
2022 size = (prefix >> 24) + to_unsigned(specs.precision);
2023 padding = to_unsigned(specs.precision - num_digits);
2028 template <
typename Char,
typename OutputIt,
typename T>
2029 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
auto write_int(OutputIt out,
write_int_arg<T> arg,
2031 static_assert(std::is_same<T, uint32_or_64_or_128_t<T>>::value,
"");
2033 constexpr
int buffer_size = num_bits<T>();
2034 char buffer[buffer_size];
2035 if (is_constant_evaluated()) fill_n(buffer, buffer_size,
'\0');
2036 const char* begin =
nullptr;
2037 const char* end = buffer + buffer_size;
2039 auto abs_value = arg.abs_value;
2040 auto prefix = arg.prefix;
2041 switch (specs.type()) {
2042 default: FMTQUILL_ASSERT(
false,
""); FMTQUILL_FALLTHROUGH;
2043 case presentation_type::none:
2044 case presentation_type::dec:
2045 begin = do_format_decimal(buffer, abs_value, buffer_size);
2047 case presentation_type::hex:
2048 begin = do_format_base2e(4, buffer, abs_value, buffer_size, specs.upper());
2050 prefix_append(prefix,
unsigned(specs.upper() ?
'X' :
'x') << 8 |
'0');
2052 case presentation_type::oct: {
2053 begin = do_format_base2e(3, buffer, abs_value, buffer_size);
2056 auto num_digits = end - begin;
2057 if (specs.alt() && specs.precision <= num_digits && abs_value != 0)
2058 prefix_append(prefix,
'0');
2061 case presentation_type::bin:
2062 begin = do_format_base2e(1, buffer, abs_value, buffer_size);
2064 prefix_append(prefix,
unsigned(specs.upper() ?
'B' :
'b') << 8 |
'0');
2066 case presentation_type::chr:
2067 return write_char<Char>(out,
static_cast<Char
>(abs_value), specs);
2073 int num_digits =
static_cast<int>(end - begin);
2075 if ((specs.width | (specs.precision + 1)) == 0) {
2076 auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24));
2077 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
2078 *it++ = static_cast<Char>(p & 0xff);
2079 return base_iterator(out, copy<Char>(begin, end, it));
2082 unsigned padding = sp.padding;
2083 return write_padded<Char, align::right>(
2084 out, specs, sp.size, [=](reserve_iterator<OutputIt> it) {
2085 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
2086 *it++ = static_cast<Char>(p & 0xff);
2087 it = detail::fill_n(it, padding, static_cast<Char>(
'0'));
2088 return copy<Char>(begin, end, it);
2092 template <
typename Char,
typename OutputIt,
typename T>
2093 FMTQUILL_CONSTEXPR FMTQUILL_NOINLINE
auto write_int_noinline(OutputIt out,
2097 return write_int<Char>(out, arg, specs);
2100 template <
typename Char,
typename T,
2102 !std::is_same<T, bool>::value &&
2103 !std::is_same<T, Char>::value)>
2107 if (specs.localized() && write_loc(out, value, specs, loc))
return out;
2108 return write_int_noinline<Char>(out, make_write_int_arg(value, specs.sign()),
2113 template <
typename Char,
typename OutputIt,
typename T,
2115 !std::is_same<T, bool>::value &&
2116 !std::is_same<T, Char>::value &&
2118 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
auto write(OutputIt out, T value,
2121 if (specs.localized() && write_loc(out, value, specs, loc))
return out;
2122 return write_int<Char>(out, make_write_int_arg(value, specs.sign()), specs);
2125 template <
typename Char,
typename OutputIt>
2128 auto data = s.
data();
2129 auto size = s.
size();
2130 if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
2131 size = code_point_index(s, to_unsigned(specs.precision));
2133 bool is_debug = specs.type() == presentation_type::debug;
2141 if (specs.width != 0) {
2145 return write_padded<Char>(
2146 out, specs, size, width, [=](reserve_iterator<OutputIt> it) {
2147 return is_debug ? write_escaped_string(it, s)
2148 : copy<Char>(data, data + size, it);
2151 template <
typename Char,
typename OutputIt>
2154 return write<Char>(out, s, specs);
2156 template <
typename Char,
typename OutputIt>
2157 FMTQUILL_CONSTEXPR
auto write(OutputIt out,
const Char* s,
const format_specs& specs,
2159 if (specs.type() == presentation_type::pointer)
2160 return write_ptr<Char>(out, bit_cast<uintptr_t>(s), &specs);
2161 if (!s) report_error(
"string pointer is null");
2165 template <
typename Char,
typename OutputIt,
typename T,
2167 !std::is_same<T, bool>::value &&
2168 !std::is_same<T, Char>::value)>
2169 FMTQUILL_CONSTEXPR
auto write(OutputIt out, T value) -> OutputIt {
2170 auto abs_value =
static_cast<uint32_or_64_or_128_t<T>
>(value);
2171 bool negative = is_negative(value);
2173 if (negative) abs_value = ~abs_value + 1;
2174 int num_digits = count_digits(abs_value);
2175 auto size = (negative ? 1 : 0) + static_cast<size_t>(num_digits);
2176 if (
auto ptr = to_pointer<Char>(out, size)) {
2177 if (negative) *ptr++ =
static_cast<Char
>(
'-');
2178 format_decimal<Char>(ptr, abs_value, num_digits);
2181 if (negative) *out++ =
static_cast<Char
>(
'-');
2182 return format_decimal<Char>(out, abs_value, num_digits);
2185 template <
typename Char>
2186 FMTQUILL_CONSTEXPR
auto parse_align(
const Char* begin,
const Char* end,
2188 FMTQUILL_ASSERT(begin != end,
"");
2189 auto alignment = align::none;
2190 auto p = begin + code_point_length(begin);
2191 if (end - p <= 0) p = begin;
2193 switch (to_ascii(*p)) {
2194 case '<': alignment = align::left;
break;
2195 case '>': alignment = align::right;
break;
2196 case '^': alignment = align::center;
break;
2198 if (alignment != align::none) {
2201 if (c ==
'}')
return begin;
2203 report_error(
"invalid fill character '{'");
2212 }
else if (p == begin) {
2217 specs.set_align(alignment);
2221 template <
typename Char,
typename OutputIt>
2222 FMTQUILL_CONSTEXPR20
auto write_nonfinite(OutputIt out,
bool isnan,
2225 isnan ? (specs.upper() ?
"NAN" :
"nan") : (specs.upper() ?
"INF" :
"inf");
2226 constexpr
size_t str_size = 3;
2227 auto size = str_size + (s != sign::none ? 1 : 0);
2229 const bool is_zero_fill =
2230 specs.fill_size() == 1 && specs.fill_unit<Char>() ==
'0';
2231 if (is_zero_fill) specs.set_fill(
' ');
2232 return write_padded<Char>(out, specs, size,
2233 [=](reserve_iterator<OutputIt> it) {
2234 if (s != sign::none)
2235 *it++ = detail::getsign<Char>(s);
2236 return copy<Char>(str, str + str_size, it);
2242 const char* significand;
2243 int significand_size;
2247 constexpr
auto get_significand_size(
const big_decimal_fp& f) ->
int {
2248 return f.significand_size;
2250 template <
typename T>
2252 return count_digits(f.significand);
2255 template <
typename Char,
typename OutputIt>
2256 constexpr
auto write_significand(OutputIt out,
const char* significand,
2257 int significand_size) -> OutputIt {
2258 return copy<Char>(significand, significand + significand_size, out);
2260 template <
typename Char,
typename OutputIt,
typename UInt>
2261 inline auto write_significand(OutputIt out, UInt significand,
2262 int significand_size) -> OutputIt {
2263 return format_decimal<Char>(out, significand, significand_size);
2265 template <
typename Char,
typename OutputIt,
typename T,
typename Grouping>
2266 FMTQUILL_CONSTEXPR20
auto write_significand(OutputIt out, T significand,
2267 int significand_size,
int exponent,
2268 const Grouping& grouping) -> OutputIt {
2269 if (!grouping.has_separator()) {
2270 out = write_significand<Char>(out, significand, significand_size);
2271 return detail::fill_n(out, exponent, static_cast<Char>(
'0'));
2274 write_significand<char>(
appender(
buffer), significand, significand_size);
2279 template <
typename Char,
typename UInt,
2280 FMTQUILL_ENABLE_IF(std::is_integral<UInt>::value)>
2281 inline auto write_significand(Char* out, UInt significand,
int significand_size,
2282 int integral_size, Char decimal_point) -> Char* {
2283 if (!decimal_point)
return format_decimal(out, significand, significand_size);
2284 out += significand_size + 1;
2286 int floating_size = significand_size - integral_size;
2287 for (
int i = floating_size / 2; i > 0; --i) {
2289 write2digits(out, static_cast<std::size_t>(significand % 100));
2292 if (floating_size % 2 != 0) {
2293 *--out =
static_cast<Char
>(
'0' + significand % 10);
2296 *--out = decimal_point;
2297 format_decimal(out - integral_size, significand, integral_size);
2301 template <
typename OutputIt,
typename UInt,
typename Char,
2302 FMTQUILL_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)>
2303 inline auto write_significand(OutputIt out, UInt significand,
2304 int significand_size,
int integral_size,
2305 Char decimal_point) -> OutputIt {
2307 Char
buffer[digits10<UInt>() + 2];
2308 auto end = write_significand(
buffer, significand, significand_size,
2309 integral_size, decimal_point);
2310 return detail::copy_noinline<Char>(
buffer, end, out);
2313 template <
typename OutputIt,
typename Char>
2314 FMTQUILL_CONSTEXPR
auto write_significand(OutputIt out,
const char* significand,
2315 int significand_size,
int integral_size,
2316 Char decimal_point) -> OutputIt {
2317 out = detail::copy_noinline<Char>(significand, significand + integral_size,
2319 if (!decimal_point)
return out;
2320 *out++ = decimal_point;
2321 return detail::copy_noinline<Char>(significand + integral_size,
2322 significand + significand_size, out);
2325 template <
typename OutputIt,
typename Char,
typename T,
typename Grouping>
2326 FMTQUILL_CONSTEXPR20
auto write_significand(OutputIt out, T significand,
2327 int significand_size,
int integral_size,
2329 const Grouping& grouping) -> OutputIt {
2330 if (!grouping.has_separator()) {
2331 return write_significand(out, significand, significand_size, integral_size,
2336 integral_size, decimal_point);
2339 return detail::copy_noinline<Char>(
buffer.
data() + integral_size,
2343 template <
typename Char,
typename OutputIt,
typename DecimalFP,
2345 FMTQUILL_CONSTEXPR20
auto do_write_float(OutputIt out,
const DecimalFP& f,
2348 auto significand = f.significand;
2349 int significand_size = get_significand_size(f);
2350 const Char zero =
static_cast<Char
>(
'0');
2351 size_t size = to_unsigned(significand_size) + (s != sign::none ? 1 : 0);
2352 using iterator = reserve_iterator<OutputIt>;
2354 Char decimal_point = specs.localized() ? detail::decimal_point<Char>(loc)
2355 : static_cast<Char>(
'.');
2357 int output_exp = f.exponent + significand_size - 1;
2358 auto use_exp_format = [=]() {
2359 if (specs.type() == presentation_type::exp)
return true;
2360 if (specs.type() == presentation_type::fixed)
return false;
2363 const int exp_lower = -4;
2364 return output_exp < exp_lower ||
2365 output_exp >= (specs.precision > 0 ? specs.precision : exp_upper);
2367 if (use_exp_format()) {
2370 num_zeros = specs.precision - significand_size;
2371 if (num_zeros < 0) num_zeros = 0;
2372 size += to_unsigned(num_zeros);
2373 }
else if (significand_size == 1) {
2374 decimal_point = Char();
2376 auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp;
2378 if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3;
2380 size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits);
2381 char exp_char = specs.upper() ?
'E' :
'e';
2382 auto write = [=](iterator it) {
2383 if (s != sign::none) *it++ = detail::getsign<Char>(s);
2385 it = write_significand(it, significand, significand_size, 1,
2387 if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero);
2388 *it++ =
static_cast<Char
>(exp_char);
2389 return write_exponent<Char>(output_exp, it);
2391 return specs.width > 0
2392 ? write_padded<Char, align::right>(out, specs, size, write)
2393 : base_iterator(out, write(reserve(out, size)));
2396 int exp = f.exponent + significand_size;
2397 if (f.exponent >= 0) {
2399 size += to_unsigned(f.exponent);
2400 int num_zeros = specs.precision - exp;
2401 abort_fuzzing_if(num_zeros > 5000);
2404 if (num_zeros <= 0 && specs.type() != presentation_type::fixed)
2406 if (num_zeros > 0) size += to_unsigned(num_zeros);
2408 auto grouping = Grouping(loc, specs.localized());
2409 size += to_unsigned(grouping.count_separators(exp));
2410 return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
2411 if (s != sign::none) *it++ = detail::getsign<Char>(s);
2412 it = write_significand<Char>(it, significand, significand_size,
2413 f.exponent, grouping);
2414 if (!specs.alt())
return it;
2415 *it++ = decimal_point;
2416 return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
2418 }
else if (exp > 0) {
2420 int num_zeros = specs.alt() ? specs.precision - significand_size : 0;
2421 size += 1 +
static_cast<unsigned>(max_of(num_zeros, 0));
2422 auto grouping = Grouping(loc, specs.localized());
2423 size += to_unsigned(grouping.count_separators(exp));
2424 return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
2425 if (s != sign::none) *it++ = detail::getsign<Char>(s);
2426 it = write_significand(it, significand, significand_size, exp,
2427 decimal_point, grouping);
2428 return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
2432 int num_zeros = -exp;
2433 if (significand_size == 0 && specs.precision >= 0 &&
2434 specs.precision < num_zeros) {
2435 num_zeros = specs.precision;
2437 bool pointy = num_zeros != 0 || significand_size != 0 || specs.alt();
2438 size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros);
2439 return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
2440 if (s != sign::none) *it++ = detail::getsign<Char>(s);
2442 if (!pointy)
return it;
2443 *it++ = decimal_point;
2444 it = detail::fill_n(it, num_zeros, zero);
2445 return write_significand<Char>(it, significand, significand_size);
2453 constexpr
auto has_separator()
const ->
bool {
return false; }
2455 constexpr
auto count_separators(
int)
const ->
int {
return 0; }
2457 template <
typename Out,
typename C>
2463 template <
typename Char,
typename OutputIt,
typename DecimalFP>
2464 FMTQUILL_CONSTEXPR20
auto write_float(OutputIt out,
const DecimalFP& f,
2467 if (is_constant_evaluated()) {
2468 return do_write_float<Char, OutputIt, DecimalFP,
2472 return do_write_float<Char>(out, f, specs, s, exp_upper, loc);
2476 template <
typename T> constexpr
auto isnan(T value) ->
bool {
2477 return value != value;
2480 template <
typename T,
typename Enable =
void>
2483 template <
typename T>
2485 : std::true_type {};
2487 template <
typename T,
2489 FMTQUILL_CONSTEXPR20
auto isfinite(T value) ->
bool {
2490 constexpr T inf = T(std::numeric_limits<double>::infinity());
2491 if (is_constant_evaluated())
2493 return std::isfinite(value);
2495 template <typename T, FMTQUILL_ENABLE_IF(!has_isfinite<T>::value)>
2496 FMTQUILL_CONSTEXPR
auto isfinite(T value) ->
bool {
2497 T inf = T(std::numeric_limits<double>::infinity());
2502 template <typename T, FMTQUILL_ENABLE_IF(is_floating_point<T>::value)>
2503 FMTQUILL_INLINE FMTQUILL_CONSTEXPR
bool signbit(T value) {
2504 if (is_constant_evaluated()) {
2505 #ifdef __cpp_if_constexpr 2506 if constexpr (std::numeric_limits<double>::is_iec559) {
2507 auto bits = detail::bit_cast<uint64_t>(
static_cast<double>(value));
2508 return (bits >> (num_bits<uint64_t>() - 1)) != 0;
2512 return std::signbit(static_cast<double>(value));
2515 inline FMTQUILL_CONSTEXPR20
void adjust_precision(
int& precision,
int exp10) {
2518 if (exp10 > 0 && precision > max_value<int>() - exp10)
2519 FMTQUILL_THROW(format_error(
"number is too big"));
2526 using bigit = uint32_t;
2527 using double_bigit = uint64_t;
2528 enum { bigit_bits = num_bits<bigit>() };
2529 enum { bigits_capacity = 32 };
2535 FMTQUILL_CONSTEXPR
auto get_bigit(
int i)
const -> bigit {
2536 return i >= exp_ && i < num_bigits() ? bigits_[i - exp_] : 0;
2539 FMTQUILL_CONSTEXPR
void subtract_bigits(
int index, bigit other, bigit& borrow) {
2540 auto result = double_bigit(bigits_[index]) - other - borrow;
2541 bigits_[index] =
static_cast<bigit
>(result);
2542 borrow =
static_cast<bigit
>(result >> (bigit_bits * 2 - 1));
2545 FMTQUILL_CONSTEXPR
void remove_leading_zeros() {
2546 int num_bigits =
static_cast<int>(bigits_.
size()) - 1;
2547 while (num_bigits > 0 && bigits_[num_bigits] == 0) --num_bigits;
2548 bigits_.
resize(to_unsigned(num_bigits + 1));
2552 FMTQUILL_CONSTEXPR
void subtract_aligned(
const bigint& other) {
2553 FMTQUILL_ASSERT(other.exp_ >= exp_,
"unaligned bigints");
2554 FMTQUILL_ASSERT(compare(*
this, other) >= 0,
"");
2556 int i = other.exp_ - exp_;
2557 for (
size_t j = 0, n = other.bigits_.
size(); j != n; ++i, ++j)
2558 subtract_bigits(i, other.bigits_[j], borrow);
2559 if (borrow != 0) subtract_bigits(i, 0, borrow);
2560 FMTQUILL_ASSERT(borrow == 0,
"");
2561 remove_leading_zeros();
2564 FMTQUILL_CONSTEXPR
void multiply(uint32_t value) {
2566 const double_bigit wide_value = value;
2567 for (
size_t i = 0, n = bigits_.
size(); i < n; ++i) {
2568 double_bigit result = bigits_[i] * wide_value + carry;
2569 bigits_[i] =
static_cast<bigit
>(result);
2570 carry =
static_cast<bigit
>(result >> bigit_bits);
2572 if (carry != 0) bigits_.push_back(carry);
2575 template <typename UInt, FMTQUILL_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
2576 std::is_same<UInt, uint128_t>::value)>
2577 FMTQUILL_CONSTEXPR
void multiply(UInt value) {
2579 conditional_t<std::is_same<UInt, uint128_t>::value, uint64_t, uint32_t>;
2580 const int shift = num_bits<half_uint>() - bigit_bits;
2581 const UInt lower =
static_cast<half_uint
>(value);
2582 const UInt upper = value >> num_bits<half_uint>();
2584 for (
size_t i = 0, n = bigits_.
size(); i < n; ++i) {
2585 UInt result = lower * bigits_[i] +
static_cast<bigit
>(carry);
2586 carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) +
2587 (carry >> bigit_bits);
2588 bigits_[i] =
static_cast<bigit
>(result);
2590 while (carry != 0) {
2591 bigits_.push_back(static_cast<bigit>(carry));
2592 carry >>= bigit_bits;
2596 template <typename UInt, FMTQUILL_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
2597 std::is_same<UInt, uint128_t>::value)>
2598 FMTQUILL_CONSTEXPR
void assign(UInt n) {
2599 size_t num_bigits = 0;
2601 bigits_[num_bigits++] =
static_cast<bigit
>(n);
2604 bigits_.
resize(num_bigits);
2609 FMTQUILL_CONSTEXPR bigint() : exp_(0) {}
2610 explicit bigint(uint64_t n) { assign(n); }
2612 bigint(
const bigint&) =
delete;
2613 void operator=(
const bigint&) =
delete;
2615 FMTQUILL_CONSTEXPR
void assign(
const bigint& other) {
2616 auto size = other.bigits_.
size();
2618 auto data = other.bigits_.
data();
2619 copy<bigit>(data, data + size, bigits_.
data());
2623 template <
typename Int> FMTQUILL_CONSTEXPR
void operator=(Int n) {
2624 FMTQUILL_ASSERT(n > 0,
"");
2625 assign(uint64_or_128_t<Int>(n));
2628 FMTQUILL_CONSTEXPR
auto num_bigits()
const ->
int {
2629 return static_cast<int>(bigits_.
size()) + exp_;
2632 FMTQUILL_CONSTEXPR
auto operator<<=(
int shift) -> bigint& {
2633 FMTQUILL_ASSERT(shift >= 0,
"");
2634 exp_ += shift / bigit_bits;
2635 shift %= bigit_bits;
2636 if (shift == 0)
return *
this;
2638 for (
size_t i = 0, n = bigits_.
size(); i < n; ++i) {
2639 bigit c = bigits_[i] >> (bigit_bits - shift);
2640 bigits_[i] = (bigits_[i] << shift) + carry;
2643 if (carry != 0) bigits_.push_back(carry);
2647 template <
typename Int> FMTQUILL_CONSTEXPR
auto operator*=(Int value) -> bigint& {
2648 FMTQUILL_ASSERT(value > 0,
"");
2649 multiply(uint32_or_64_or_128_t<Int>(value));
2653 friend FMTQUILL_CONSTEXPR
auto compare(
const bigint& b1,
const bigint& b2) ->
int {
2654 int num_bigits1 = b1.num_bigits(), num_bigits2 = b2.num_bigits();
2655 if (num_bigits1 != num_bigits2)
return num_bigits1 > num_bigits2 ? 1 : -1;
2656 int i =
static_cast<int>(b1.bigits_.
size()) - 1;
2657 int j =
static_cast<int>(b2.bigits_.
size()) - 1;
2659 if (end < 0) end = 0;
2660 for (; i >= end; --i, --j) {
2661 bigit b1_bigit = b1.bigits_[i], b2_bigit = b2.bigits_[j];
2662 if (b1_bigit != b2_bigit)
return b1_bigit > b2_bigit ? 1 : -1;
2664 if (i != j)
return i > j ? 1 : -1;
2669 friend FMTQUILL_CONSTEXPR
auto add_compare(
const bigint& lhs1,
const bigint& lhs2,
2670 const bigint& rhs) ->
int {
2671 int max_lhs_bigits = max_of(lhs1.num_bigits(), lhs2.num_bigits());
2672 int num_rhs_bigits = rhs.num_bigits();
2673 if (max_lhs_bigits + 1 < num_rhs_bigits)
return -1;
2674 if (max_lhs_bigits > num_rhs_bigits)
return 1;
2675 double_bigit borrow = 0;
2676 int min_exp = min_of(min_of(lhs1.exp_, lhs2.exp_), rhs.exp_);
2677 for (
int i = num_rhs_bigits - 1; i >= min_exp; --i) {
2678 double_bigit sum = double_bigit(lhs1.get_bigit(i)) + lhs2.get_bigit(i);
2679 bigit rhs_bigit = rhs.get_bigit(i);
2680 if (sum > rhs_bigit + borrow)
return 1;
2681 borrow = rhs_bigit + borrow - sum;
2682 if (borrow > 1)
return -1;
2683 borrow <<= bigit_bits;
2685 return borrow != 0 ? -1 : 0;
2689 FMTQUILL_CONSTEXPR20
void assign_pow10(
int exp) {
2690 FMTQUILL_ASSERT(exp >= 0,
"");
2691 if (exp == 0)
return *
this = 1;
2692 int bitmask = 1 << (num_bits<unsigned>() -
2693 countl_zero(static_cast<uint32_t>(exp)) - 1);
2698 while (bitmask != 0) {
2700 if ((exp & bitmask) != 0) *
this *= 5;
2706 FMTQUILL_CONSTEXPR20
void square() {
2707 int num_bigits =
static_cast<int>(bigits_.
size());
2708 int num_result_bigits = 2 * num_bigits;
2710 bigits_.
resize(to_unsigned(num_result_bigits));
2711 auto sum = uint128_t();
2712 for (
int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) {
2715 for (
int i = 0, j = bigit_index; j >= 0; ++i, --j) {
2717 sum += double_bigit(n[i]) * n[j];
2719 bigits_[bigit_index] =
static_cast<bigit
>(sum);
2720 sum >>= num_bits<bigit>();
2723 for (
int bigit_index = num_bigits; bigit_index < num_result_bigits;
2725 for (
int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;)
2726 sum += double_bigit(n[i++]) * n[j--];
2727 bigits_[bigit_index] =
static_cast<bigit
>(sum);
2728 sum >>= num_bits<bigit>();
2730 remove_leading_zeros();
2736 FMTQUILL_CONSTEXPR
void align(
const bigint& other) {
2737 int exp_difference = exp_ - other.exp_;
2738 if (exp_difference <= 0)
return;
2739 int num_bigits =
static_cast<int>(bigits_.
size());
2740 bigits_.
resize(to_unsigned(num_bigits + exp_difference));
2741 for (
int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j)
2742 bigits_[j] = bigits_[i];
2743 memset(bigits_.
data(), 0, to_unsigned(exp_difference) *
sizeof(bigit));
2744 exp_ -= exp_difference;
2749 FMTQUILL_CONSTEXPR
auto divmod_assign(
const bigint& divisor) ->
int {
2750 FMTQUILL_ASSERT(
this != &divisor,
"");
2751 if (compare(*
this, divisor) < 0)
return 0;
2752 FMTQUILL_ASSERT(divisor.bigits_[divisor.bigits_.
size() - 1u] != 0,
"");
2756 subtract_aligned(divisor);
2758 }
while (compare(*
this, divisor) >= 0);
2765 predecessor_closer = 1,
2774 unsigned flags,
int num_digits,
2785 bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0;
2786 int shift = is_predecessor_closer ? 2 : 1;
2788 numerator = value.f;
2789 numerator <<= value.e + shift;
2792 if (is_predecessor_closer) {
2794 upper_store <<= value.e + 1;
2795 upper = &upper_store;
2797 denominator.assign_pow10(exp10);
2798 denominator <<= shift;
2799 }
else if (exp10 < 0) {
2800 numerator.assign_pow10(-exp10);
2801 lower.assign(numerator);
2802 if (is_predecessor_closer) {
2803 upper_store.assign(numerator);
2805 upper = &upper_store;
2807 numerator *= value.f;
2808 numerator <<= shift;
2810 denominator <<= shift - value.e;
2812 numerator = value.f;
2813 numerator <<= shift;
2814 denominator.assign_pow10(exp10);
2815 denominator <<= shift - value.e;
2817 if (is_predecessor_closer) {
2818 upper_store = 1ULL << 1;
2819 upper = &upper_store;
2822 int even =
static_cast<int>((value.f & 1) == 0);
2823 if (!upper) upper = &lower;
2824 bool shortest = num_digits < 0;
2825 if ((flags & dragon::fixup) != 0) {
2826 if (add_compare(numerator, *upper, denominator) + even <= 0) {
2829 if (num_digits < 0) {
2831 if (upper != &lower) *upper *= 10;
2834 if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1);
2840 char* data = buf.
data();
2842 int digit = numerator.divmod_assign(denominator);
2843 bool low = compare(numerator, lower) - even < 0;
2845 bool high = add_compare(numerator, *upper, denominator) + even > 0;
2846 data[num_digits++] =
static_cast<char>(
'0' + digit);
2849 ++data[num_digits - 1];
2851 int result = add_compare(numerator, numerator, denominator);
2853 if (result > 0 || (result == 0 && (digit % 2) != 0))
2854 ++data[num_digits - 1];
2856 buf.try_resize(to_unsigned(num_digits));
2857 exp10 -= num_digits - 1;
2862 if (upper != &lower) *upper *= 10;
2866 exp10 -= num_digits - 1;
2867 if (num_digits <= 0) {
2869 if (num_digits == 0) {
2871 digit = add_compare(numerator, numerator, denominator) > 0 ?
'1' :
'0';
2873 buf.push_back(digit);
2876 buf.try_resize(to_unsigned(num_digits));
2877 for (
int i = 0; i < num_digits - 1; ++i) {
2878 int digit = numerator.divmod_assign(denominator);
2879 buf[i] =
static_cast<char>(
'0' + digit);
2882 int digit = numerator.divmod_assign(denominator);
2883 auto result = add_compare(numerator, numerator, denominator);
2884 if (result > 0 || (result == 0 && (digit % 2) != 0)) {
2886 const auto overflow =
'0' + 10;
2887 buf[num_digits - 1] = overflow;
2889 for (
int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) {
2893 if (buf[0] == overflow) {
2895 if ((flags & dragon::fixed) != 0)
2904 buf[num_digits - 1] =
static_cast<char>(
'0' + digit);
2908 template <typename Float, FMTQUILL_ENABLE_IF(!is_double_double<Float>::value)>
2909 FMTQUILL_CONSTEXPR20
void format_hexfloat(Float value,
format_specs specs,
2913 static_assert(!std::is_same<Float, float>::value,
"");
2918 using carrier_uint =
typename info::carrier_uint;
2920 const auto num_float_significand_bits = detail::num_significand_bits<Float>();
2923 f.e += num_float_significand_bits;
2924 if (!has_implicit_bit<Float>()) --f.e;
2926 const auto num_fraction_bits =
2927 num_float_significand_bits + (has_implicit_bit<Float>() ? 1 : 0);
2928 const auto num_xdigits = (num_fraction_bits + 3) / 4;
2930 const auto leading_shift = ((num_xdigits - 1) * 4);
2931 const auto leading_mask = carrier_uint(0xF) << leading_shift;
2932 const auto leading_xdigit =
2933 static_cast<uint32_t
>((f.f & leading_mask) >> leading_shift);
2934 if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1);
2936 int print_xdigits = num_xdigits - 1;
2937 if (specs.precision >= 0 && print_xdigits > specs.precision) {
2938 const int shift = ((print_xdigits - specs.precision - 1) * 4);
2939 const auto mask = carrier_uint(0xF) << shift;
2940 const auto v =
static_cast<uint32_t
>((f.f & mask) >> shift);
2943 const auto inc = carrier_uint(1) << (shift + 4);
2949 if (!has_implicit_bit<Float>()) {
2950 const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
2951 if ((f.f & implicit_bit) == implicit_bit) {
2957 print_xdigits = specs.precision;
2960 char xdigits[num_bits<carrier_uint>() / 4];
2961 detail::fill_n(xdigits,
sizeof(xdigits),
'0');
2962 format_base2e(4, xdigits, f.f, num_xdigits, specs.upper());
2965 while (print_xdigits > 0 && xdigits[print_xdigits] ==
'0') --print_xdigits;
2968 buf.push_back(specs.upper() ?
'X' :
'x');
2969 buf.push_back(xdigits[0]);
2970 if (specs.alt() || print_xdigits > 0 || print_xdigits < specs.precision)
2972 buf.
append(xdigits + 1, xdigits + 1 + print_xdigits);
2973 for (; print_xdigits < specs.precision; ++print_xdigits) buf.push_back(
'0');
2975 buf.push_back(specs.upper() ?
'P' :
'p');
2980 abs_e =
static_cast<uint32_t
>(-f.e);
2983 abs_e =
static_cast<uint32_t
>(f.e);
2985 format_decimal<char>(
appender(buf), abs_e, detail::count_digits(abs_e));
2988 template <typename Float, FMTQUILL_ENABLE_IF(is_double_double<Float>::value)>
2989 FMTQUILL_CONSTEXPR20
void format_hexfloat(Float value,
format_specs specs,
2991 format_hexfloat(static_cast<double>(value), specs, buf);
2994 constexpr
auto fractional_part_rounding_thresholds(
int index) -> uint32_t {
3001 return U
"\x9999999a\x828f5c29\x80418938\x80068db9\x8000a7c6\x800010c7" 3002 U
"\x800001ae\x8000002b"[index];
3005 template <
typename Float>
3006 FMTQUILL_CONSTEXPR20
auto format_float(Float value,
int precision,
3010 static_assert(!std::is_same<Float, float>::value,
"");
3011 auto converted_value = convert_float(value);
3013 const bool fixed = specs.type() == presentation_type::fixed;
3015 if (precision <= 0 || !fixed) {
3019 buf.try_resize(to_unsigned(precision));
3020 fill_n(buf.
data(), precision,
'0');
3025 bool use_dragon =
true;
3026 unsigned dragon_flags = 0;
3027 if (!is_fast_float<Float>() || is_constant_evaluated()) {
3028 const auto inv_log2_10 = 0.3010299956639812;
3035 auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10;
3036 exp =
static_cast<int>(e);
3038 dragon_flags = dragon::fixup;
3042 auto br = bit_cast<uint64_t>(
static_cast<double>(value));
3044 const uint64_t significand_mask =
3045 (
static_cast<uint64_t
>(1) << num_significand_bits<double>()) - 1;
3046 uint64_t significand = (br & significand_mask);
3047 int exponent =
static_cast<int>((br & exponent_mask<double>()) >>
3048 num_significand_bits<double>());
3050 if (exponent != 0) {
3051 exponent -= exponent_bias<double>() + num_significand_bits<double>();
3053 (
static_cast<uint64_t
>(1) << num_significand_bits<double>());
3057 FMTQUILL_ASSERT(significand != 0,
"zeros should not appear here");
3058 int shift = countl_zero(significand);
3059 FMTQUILL_ASSERT(shift >= num_bits<uint64_t>() - num_significand_bits<double>(),
3061 shift -= (num_bits<uint64_t>() - num_significand_bits<double>() - 2);
3062 exponent = (std::numeric_limits<double>::min_exponent -
3063 num_significand_bits<double>()) -
3065 significand <<= shift;
3070 const int k = info::kappa - dragonbox::floor_log10_pow2(exponent);
3072 const int beta = exponent + dragonbox::floor_log2_pow10(k);
3073 uint64_t first_segment;
3074 bool has_more_segments;
3075 int digits_in_the_first_segment;
3077 const auto r = dragonbox::umul192_upper128(
3078 significand << beta, dragonbox::get_cached_power(k));
3079 first_segment = r.high();
3080 has_more_segments = r.low() != 0;
3083 if (first_segment >= 1000000000000000000ULL) {
3084 digits_in_the_first_segment = 19;
3088 digits_in_the_first_segment = 18;
3089 first_segment *= 10;
3094 if (fixed) adjust_precision(precision, exp + digits_in_the_first_segment);
3098 if (digits_in_the_first_segment > precision) {
3101 if (precision <= 0) {
3102 exp += digits_in_the_first_segment;
3104 if (precision < 0) {
3110 if ((first_segment | static_cast<uint64_t>(has_more_segments)) >
3111 5000000000000000000ULL) {
3119 exp += digits_in_the_first_segment - precision;
3128 const uint32_t first_subsegment =
static_cast<uint32_t
>(
3129 dragonbox::umul128_upper64(first_segment, 7922816251426433760ULL) >>
3131 const uint64_t second_third_subsegments =
3132 first_segment - first_subsegment * 10000000000ULL;
3136 bool should_round_up;
3137 int number_of_digits_to_print = min_of(precision, 9);
3140 auto print_subsegment = [&](uint32_t subsegment,
char*
buffer) {
3141 int number_of_digits_printed = 0;
3144 if ((number_of_digits_to_print & 1) != 0) {
3150 prod = ((subsegment *
static_cast<uint64_t
>(720575941)) >> 24) + 1;
3151 digits =
static_cast<uint32_t
>(prod >> 32);
3152 *
buffer =
static_cast<char>(
'0' + digits);
3153 number_of_digits_printed++;
3163 prod = ((subsegment *
static_cast<uint64_t
>(450359963)) >> 20) + 1;
3164 digits =
static_cast<uint32_t
>(prod >> 32);
3165 write2digits(
buffer, digits);
3166 number_of_digits_printed += 2;
3170 while (number_of_digits_printed < number_of_digits_to_print) {
3171 prod =
static_cast<uint32_t
>(prod) * static_cast<uint64_t>(100);
3172 digits =
static_cast<uint32_t
>(prod >> 32);
3173 write2digits(
buffer + number_of_digits_printed, digits);
3174 number_of_digits_printed += 2;
3179 print_subsegment(first_subsegment, buf.
data());
3183 if (precision <= 9) {
3197 if (precision < 9) {
3198 uint32_t fractional_part =
static_cast<uint32_t
>(prod);
3200 fractional_part >= fractional_part_rounding_thresholds(
3201 8 - number_of_digits_to_print) ||
3202 ((fractional_part >> 31) &
3203 ((digits & 1) | (second_third_subsegments != 0) |
3204 has_more_segments)) != 0;
3212 should_round_up = second_third_subsegments > 5000000000ULL ||
3213 (second_third_subsegments == 5000000000ULL &&
3214 ((digits & 1) != 0 || has_more_segments));
3223 const uint32_t second_subsegment =
3224 static_cast<uint32_t
>(dragonbox::umul128_upper64(
3225 second_third_subsegments, 1844674407370955162ULL));
3226 const uint32_t third_subsegment =
3227 static_cast<uint32_t
>(second_third_subsegments) -
3228 second_subsegment * 10;
3230 number_of_digits_to_print = precision - 9;
3231 print_subsegment(second_subsegment, buf.
data() + 9);
3234 if (precision < 18) {
3238 uint32_t fractional_part =
static_cast<uint32_t
>(prod);
3240 fractional_part >= fractional_part_rounding_thresholds(
3241 8 - number_of_digits_to_print) ||
3242 ((fractional_part >> 31) &
3243 ((digits & 1) | (third_subsegment != 0) |
3244 has_more_segments)) != 0;
3251 should_round_up = third_subsegment > 5 ||
3252 (third_subsegment == 5 &&
3253 ((digits & 1) != 0 || has_more_segments));
3258 if (should_round_up) {
3259 ++buf[precision - 1];
3260 for (
int i = precision - 1; i > 0 && buf[i] >
'9'; --i) {
3267 buf[precision++] =
'0';
3272 buf.try_resize(to_unsigned(precision));
3277 exp += digits_in_the_first_segment - 1;
3282 bool is_predecessor_closer = binary32 ? f.assign(static_cast<float>(value))
3283 : f.assign(converted_value);
3284 if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer;
3285 if (fixed) dragon_flags |= dragon::fixed;
3288 const int max_double_digits = 767;
3289 if (precision > max_double_digits) precision = max_double_digits;
3290 format_dragon(f, dragon_flags, precision, buf, exp);
3292 if (!fixed && !specs.alt()) {
3294 auto num_digits = buf.
size();
3295 while (num_digits > 0 && buf[num_digits - 1] ==
'0') {
3299 buf.try_resize(num_digits);
3306 template <
typename T> constexpr
auto exp_upper() ->
int {
3307 return std::numeric_limits<T>::digits10 != 0
3308 ? min_of(16, std::numeric_limits<T>::digits10 + 1)
3312 template <
typename Char,
typename OutputIt,
typename T>
3313 FMTQUILL_CONSTEXPR20
auto write_float(OutputIt out, T value,
format_specs specs,
3316 sign s = detail::signbit(value) ? sign::minus : specs.sign();
3318 if (!detail::isfinite(value))
3319 return write_nonfinite<Char>(out, detail::isnan(value), specs, s);
3321 if (specs.align() == align::numeric && s != sign::none) {
3322 *out++ = detail::getsign<Char>(s);
3324 if (specs.width != 0) --specs.width;
3327 constexpr
int exp_upper = detail::exp_upper<T>();
3328 int precision = specs.precision;
3329 if (precision < 0) {
3330 if (specs.type() != presentation_type::none) {
3332 }
else if (is_fast_float<T>::value && !is_constant_evaluated()) {
3334 using floaty = conditional_t<sizeof(T) >=
sizeof(double),
double,
float>;
3335 auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
3336 return write_float<Char>(out, dec, specs, s, exp_upper, loc);
3341 if (specs.type() == presentation_type::hexfloat) {
3342 if (s != sign::none) buffer.push_back(detail::getsign<char>(s));
3343 format_hexfloat(convert_float(value), specs, buffer);
3344 return write_bytes<Char, align::right>(out, {buffer.data(), buffer.size()},
3348 if (specs.type() == presentation_type::exp) {
3349 if (precision == max_value<int>())
3350 report_error(
"number is too big");
3353 if (specs.precision != 0) specs.set_alt();
3354 }
else if (specs.type() == presentation_type::fixed) {
3355 if (specs.precision != 0) specs.set_alt();
3356 }
else if (precision == 0) {
3359 int exp = format_float(convert_float(value), precision, specs,
3360 std::is_same<T, float>(), buffer);
3362 specs.precision = precision;
3363 auto f =
big_decimal_fp{buffer.data(),
static_cast<int>(buffer.size()), exp};
3364 return write_float<Char>(out, f, specs, s, exp_upper, loc);
3367 template <
typename Char,
typename OutputIt,
typename T,
3369 FMTQUILL_CONSTEXPR20
auto write(OutputIt out, T value,
format_specs specs,
3371 return specs.localized() && write_loc(out, value, specs, loc)
3373 : write_float<Char>(out, value, specs, loc);
3376 template <
typename Char,
typename OutputIt,
typename T,
3377 FMTQUILL_ENABLE_IF(is_fast_float<T>::value)>
3378 FMTQUILL_CONSTEXPR20
auto write(OutputIt out, T value) -> OutputIt {
3379 if (is_constant_evaluated())
return write<Char>(out, value,
format_specs());
3381 auto s = detail::signbit(value) ? sign::minus : sign::none;
3384 using floaty = conditional_t<sizeof(T) >=
sizeof(double),
double,
float>;
3386 floaty_uint mask = exponent_mask<floaty>();
3387 if ((bit_cast<floaty_uint>(value) & mask) == mask)
3388 return write_nonfinite<Char>(out, std::isnan(value), specs, s);
3390 auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
3391 return write_float<Char>(out, dec, specs, s, exp_upper<T>(), {});
3394 template <
typename Char,
typename OutputIt,
typename T,
3396 !is_fast_float<T>::value)>
3397 inline auto write(OutputIt out, T value) -> OutputIt {
3401 template <
typename Char,
typename OutputIt>
3404 FMTQUILL_ASSERT(
false,
"");
3408 template <
typename Char,
typename OutputIt>
3411 return copy_noinline<Char>(value.begin(), value.end(), out);
3414 template <
typename Char,
typename OutputIt,
typename T,
3416 constexpr
auto write(OutputIt out,
const T& value) -> OutputIt {
3417 return write<Char>(out, to_string_view(value));
3422 typename Char,
typename OutputIt,
typename T,
3423 bool check = std::is_enum<T>::value && !std::is_same<T, Char>::value &&
3425 FMTQUILL_ENABLE_IF(check)>
3426 FMTQUILL_CONSTEXPR
auto write(OutputIt out, T value) -> OutputIt {
3427 return write<Char>(out,
static_cast<underlying_t<T>
>(value));
3430 template <
typename Char,
typename OutputIt,
typename T,
3431 FMTQUILL_ENABLE_IF(std::is_same<T, bool>::value)>
3432 FMTQUILL_CONSTEXPR
auto write(OutputIt out, T value,
const format_specs& specs = {},
3434 return specs.type() != presentation_type::none &&
3435 specs.type() != presentation_type::string
3436 ? write<Char>(out, value ? 1 : 0, specs, {})
3437 : write_bytes<Char>(out, value ?
"true" :
"false", specs);
3440 template <
typename Char,
typename OutputIt>
3441 FMTQUILL_CONSTEXPR
auto write(OutputIt out, Char value) -> OutputIt {
3442 auto it = reserve(out, 1);
3444 return base_iterator(out, it);
3447 template <
typename Char,
typename OutputIt>
3448 FMTQUILL_CONSTEXPR20
auto write(OutputIt out,
const Char* value) -> OutputIt {
3450 report_error(
"string pointer is null");
3454 template <
typename Char,
typename OutputIt,
typename T,
3455 FMTQUILL_ENABLE_IF(std::is_same<T, void>::value)>
3456 auto write(OutputIt out,
const T* value,
const format_specs& specs = {},
3458 return write_ptr<Char>(out, bit_cast<uintptr_t>(value), &specs);
3461 template <
typename Char,
typename OutputIt,
typename T,
3463 type::custom_type &&
3464 !std::is_fundamental<T>::value)>
3465 FMTQUILL_CONSTEXPR
auto write(OutputIt out,
const T& value) -> OutputIt {
3469 auto ctx = basic_format_context<OutputIt, Char>(out, {}, {});
3470 return f.format(value, ctx);
3473 template <
typename T>
3475 bool_constant<std::is_same<T, int>::value || FMTQUILL_BUILTIN_TYPES>;
3480 using context = buffered_context<Char>;
3484 void operator()(
monostate) { report_error(
"argument not found"); }
3486 template <typename T, FMTQUILL_ENABLE_IF(is_builtin<T>::value)>
3487 void operator()(T value) {
3488 write<Char>(out, value);
3491 template <typename T, FMTQUILL_ENABLE_IF(!is_builtin<T>::value)>
3492 void operator()(T) {
3493 FMTQUILL_ASSERT(
false,
"");
3499 auto format_ctx =
context(out, {}, {});
3500 h.format(parse_ctx, format_ctx);
3507 FMTQUILL_NO_UNIQUE_ADDRESS
locale_ref locale;
3509 template <typename T, FMTQUILL_ENABLE_IF(is_builtin<T>::value)>
3510 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
void operator()(T value) {
3511 detail::write<Char>(out, value, specs, locale);
3514 template <typename T, FMTQUILL_ENABLE_IF(!is_builtin<T>::value)>
3515 void operator()(T) {
3516 FMTQUILL_ASSERT(
false,
"");
3519 void operator()(
typename basic_format_arg<buffered_context<Char>>::handle) {
3526 template <typename T, FMTQUILL_ENABLE_IF(is_integer<T>::value)>
3527 FMTQUILL_CONSTEXPR
auto operator()(T value) ->
unsigned long long {
3528 return is_negative(value) ? ~0ull :
static_cast<unsigned long long>(value);
3531 template <typename T, FMTQUILL_ENABLE_IF(!is_integer<T>::value)>
3532 FMTQUILL_CONSTEXPR
auto operator()(T) ->
unsigned long long {
3533 report_error(
"width/precision is not integer");
3538 template <
typename Context,
typename ID>
3540 auto arg = ctx.arg(
id);
3541 if (!arg) report_error(
"argument not found");
3545 template <
typename Context>
3546 FMTQUILL_CONSTEXPR
int get_dynamic_spec(
3549 FMTQUILL_ASSERT(kind != arg_id_kind::none,
"");
3551 kind == arg_id_kind::index ? ctx.arg(ref.index) : ctx.arg(ref.name);
3552 if (!arg) report_error(
"argument not found");
3554 if (value > to_unsigned(max_value<int>()))
3555 report_error(
"width/precision is out of range");
3556 return static_cast<int>(value);
3559 template <
typename Context>
3560 FMTQUILL_CONSTEXPR
void handle_dynamic_spec(
3561 arg_id_kind kind,
int& value,
3563 if (kind != arg_id_kind::none) value = get_dynamic_spec(kind, ref, ctx);
3566 #if FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 3567 template <
typename T,
typename Char,
size_t N,
3568 fmtquill::detail::fixed_string<Char, N> Str>
3569 struct static_named_arg :
view {
3570 static constexpr
auto name = Str.data;
3573 static_named_arg(
const T& v) : value(v) {}
3576 template <
typename T,
typename Char,
size_t N,
3577 fmtquill::detail::fixed_string<Char, N> Str>
3578 struct is_named_arg<static_named_arg<T, Char, N, Str>> : std::true_type {};
3580 template <
typename T,
typename Char,
size_t N,
3581 fmtquill::detail::fixed_string<Char, N> Str>
3585 template <
typename Char,
size_t N, fmtquill::detail::fixed_
string<Char, N> Str>
3587 template <
typename T>
auto operator=(T&& value)
const {
3588 return static_named_arg<T, Char, N, Str>(std::forward<T>(value));
3596 return {str, std::forward<T>(value)};
3599 #endif // FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 3603 buffered_context<Char> ctx;
3605 void on_text(
const Char* begin,
const Char* end) {
3606 copy_noinline<Char>(begin, end, ctx.out());
3609 FMTQUILL_CONSTEXPR
auto on_arg_id() ->
int {
return parse_ctx.
next_arg_id(); }
3610 FMTQUILL_CONSTEXPR
auto on_arg_id(
int id) ->
int {
3616 int arg_id = ctx.arg_id(
id);
3617 if (arg_id < 0) report_error(
"argument not found");
3621 FMTQUILL_INLINE
void on_replacement_field(
int id,
const Char*) {
3625 auto on_format_specs(
int id,
const Char* begin,
const Char* end)
3627 auto arg = get_arg(ctx,
id);
3629 if (arg.format_custom(begin, parse_ctx, ctx))
return parse_ctx.
begin();
3632 begin = parse_format_specs(begin, end, specs, parse_ctx, arg.type());
3633 if (specs.dynamic()) {
3634 handle_dynamic_spec(specs.dynamic_width(), specs.width, specs.width_ref,
3636 handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
3637 specs.precision_ref, ctx);
3644 FMTQUILL_NORETURN
void on_error(
const char* message) { report_error(message); }
3648 FMTQUILL_API
void do_report_error(format_func func,
int error_code,
3649 const char* message) noexcept;
3651 FMTQUILL_API
void format_error_code(
buffer<char>& out,
int error_code,
3654 template <
typename T,
typename Char, type TYPE>
3655 template <
typename FormatContext>
3657 const T& val, FormatContext& ctx)
const -> decltype(ctx.out()) {
3658 if (!specs_.dynamic())
3659 return write<Char>(ctx.out(), val, specs_, ctx.locale());
3661 handle_dynamic_spec(specs.dynamic_width(), specs.width, specs_.width_ref,
3663 handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
3664 specs_.precision_ref, ctx);
3665 return write<Char>(ctx.out(), val, specs, ctx.locale());
3669 template <
typename T,
typename Enable =
void>
3671 template <
typename T>
3672 struct is_locale<T, void_t<decltype(T::classic())>> : std::true_type {};
3682 template <
typename Char>
3686 parse_format_string(
3691 FMTQUILL_BEGIN_EXPORT
3703 using char_type = Char;
3704 using iterator = OutputIt;
3706 template <
typename T>
3708 enum { builtin_types = FMTQUILL_BUILTIN_TYPES };
3713 : out_(out), args_(args), loc_(loc) {}
3719 return args_.
get(
id);
3723 return args_.
get(name);
3726 return args_.get_id(name);
3729 constexpr
auto out()
const -> iterator {
return out_; }
3731 void advance_to(iterator it) {
3743 template <typename T, FMTQUILL_ENABLE_IF(!detail::is_float128<T>::value)>
3746 template <typename T, FMTQUILL_ENABLE_IF(detail::is_float128<T>::value)>
3749 template <
typename Visitor>
auto visit(Visitor&& vis) -> decltype(vis(0)) {
3750 return value_.
visit(vis);
3758 std::string separator_;
3759 std::string grouping_;
3760 std::string decimal_point_;
3767 static FMTQUILL_API
typename Locale::id id;
3771 std::string decimal_point =
".")
3772 : separator_(sep.data(), sep.size()),
3773 grouping_(grouping),
3774 decimal_point_(decimal_point) {}
3778 return do_put(out, val, specs);
3782 #define FMTQUILL_FORMAT_AS(Type, Base) \ 3783 template <typename Char> \ 3784 struct formatter<Type, Char> : formatter<Base, Char> { \ 3785 template <typename FormatContext> \ 3786 FMTQUILL_CONSTEXPR auto format(Type value, FormatContext& ctx) const \ 3787 -> decltype(ctx.out()) { \ 3788 return formatter<Base, Char>::format(value, ctx); \ 3792 FMTQUILL_FORMAT_AS(
signed char,
int);
3793 FMTQUILL_FORMAT_AS(
unsigned char,
unsigned);
3794 FMTQUILL_FORMAT_AS(
short,
int);
3795 FMTQUILL_FORMAT_AS(
unsigned short,
unsigned);
3796 FMTQUILL_FORMAT_AS(
long, detail::long_type);
3797 FMTQUILL_FORMAT_AS(
unsigned long, detail::ulong_type);
3798 FMTQUILL_FORMAT_AS(Char*,
const Char*);
3800 FMTQUILL_FORMAT_AS(std::nullptr_t,
const void*);
3801 FMTQUILL_FORMAT_AS(
void*,
const void*);
3803 template <
typename Char,
size_t N>
3806 template <
typename Char,
typename Traits,
typename Allocator>
3807 class formatter<std::basic_string<Char, Traits, Allocator>, Char>
3808 :
public formatter<basic_string_view<Char>, Char> {};
3810 template <
int N,
typename Char>
3812 template <
int N,
typename Char>
3814 :
formatter<unsigned long long, Char> {};
3816 template <
typename Char>
3819 detail::type::float_type> {};
3821 template <
typename T,
typename Char>
3822 struct formatter<T, Char, void_t<detail::format_as_result<T>>>
3823 :
formatter<detail::format_as_result<T>, Char> {
3824 template <
typename FormatContext>
3825 FMTQUILL_CONSTEXPR
auto format(
const T& value, FormatContext& ctx)
const 3826 -> decltype(ctx.out()) {
3827 auto&& val = format_as(value);
3839 template <
typename T>
auto ptr(T p) ->
const void* {
3840 static_assert(std::is_pointer<T>::value,
"");
3841 return detail::bit_cast<
const void*>(p);
3852 template <
typename Enum>
3853 constexpr
auto underlying(Enum e) noexcept -> underlying_t<Enum> {
3854 return static_cast<underlying_t<Enum>
>(e);
3858 template <typename Enum, FMTQUILL_ENABLE_IF(std::is_enum<Enum>::value)>
3859 constexpr
auto format_as(Enum e) noexcept -> underlying_t<Enum> {
3860 return static_cast<underlying_t<Enum>
>(e);
3864 #ifdef __cpp_lib_byte 3866 static auto format_as(std::byte b) ->
unsigned char {
3867 return static_cast<unsigned char>(b);
3869 template <
typename Context>
3870 auto format(std::byte b, Context& ctx)
const -> decltype(ctx.out()) {
3888 return parse_format_specs(ctx.
begin(), ctx.
end(), specs_, ctx,
3889 detail::type::string_type);
3892 template <
typename FormatContext>
3893 auto format(
bytes b, FormatContext& ctx)
const -> decltype(ctx.out()) {
3894 auto specs = specs_;
3895 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
3896 specs.width_ref, ctx);
3897 detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
3898 specs.precision_ref, ctx);
3899 return detail::write_bytes<char>(ctx.out(), b.data, specs);
3927 return parse_format_specs(ctx.
begin(), ctx.
end(), specs_, ctx,
3928 detail::type::int_type);
3931 template <
typename FormatContext>
3933 -> decltype(ctx.out()) {
3934 auto specs = specs_;
3935 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
3936 specs.width_ref, ctx);
3937 detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
3938 specs.precision_ref, ctx);
3939 auto arg = detail::make_write_int_arg(view.value, specs.sign());
3940 return detail::write_int(
3941 ctx.out(),
static_cast<detail::uint64_or_128_t<T>
>(arg.abs_value),
3951 template <
typename T,
typename Char>
3956 template <
typename FormatContext>
3958 -> decltype(ctx.out()) {
3959 return view.fmt->format(*view.value, ctx);
3973 auto it = ctx.
begin(), end = ctx.
end();
3974 if (it == end)
return it;
3976 it = detail::parse_align(it, end, specs);
3980 if ((c >=
'0' && c <=
'9') || c ==
'{') {
3981 it = detail::parse_width(it, end, specs, width_ref, ctx);
3982 width_ = specs.width;
3985 return formatter_.parse(ctx);
3988 template <
typename FormatContext,
typename F>
3989 auto write_padded(FormatContext& ctx, F write)
const -> decltype(ctx.out()) {
3990 if (width_ == 0)
return write(ctx.out());
3994 specs.width = width_;
3995 specs.copy_fill_from(specs_);
3996 specs.set_align(specs_.align());
3997 return detail::write<Char>(
4007 #if FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 4008 template <detail::fixed_
string S> constexpr
auto operator""_a() {
4009 using char_t = remove_cvref_t<decltype(*S.data)>;
4024 #endif // FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 4032 enum { buffer_size = std::numeric_limits<unsigned long long>::digits10 + 3 };
4033 mutable char buffer_[buffer_size];
4036 template <
typename UInt>
4037 FMTQUILL_CONSTEXPR20
auto format_unsigned(UInt value) ->
char* {
4038 auto n =
static_cast<detail::uint32_or_64_or_128_t<UInt>
>(value);
4039 return detail::do_format_decimal(buffer_, n, buffer_size - 1);
4042 template <
typename Int>
4043 FMTQUILL_CONSTEXPR20
auto format_signed(Int value) ->
char* {
4044 auto abs_value =
static_cast<detail::uint32_or_64_or_128_t<Int>
>(value);
4045 bool negative = value < 0;
4046 if (negative) abs_value = 0 - abs_value;
4047 auto begin = format_unsigned(abs_value);
4048 if (negative) *--begin =
'-';
4053 FMTQUILL_CONSTEXPR20
explicit format_int(
int value) : str_(format_signed(value)) {}
4054 FMTQUILL_CONSTEXPR20
explicit format_int(
long value)
4055 : str_(format_signed(value)) {}
4056 FMTQUILL_CONSTEXPR20
explicit format_int(
long long value)
4057 : str_(format_signed(value)) {}
4058 FMTQUILL_CONSTEXPR20
explicit format_int(
unsigned value)
4059 : str_(format_unsigned(value)) {}
4060 FMTQUILL_CONSTEXPR20
explicit format_int(
unsigned long value)
4061 : str_(format_unsigned(value)) {}
4062 FMTQUILL_CONSTEXPR20
explicit format_int(
unsigned long long value)
4063 : str_(format_unsigned(value)) {}
4066 FMTQUILL_CONSTEXPR20
auto size() const ->
size_t {
4067 return detail::to_unsigned(buffer_ - str_ + buffer_size - 1);
4072 FMTQUILL_CONSTEXPR20
auto data() const -> const
char* {
return str_; }
4076 FMTQUILL_CONSTEXPR20
auto c_str() const -> const
char* {
4077 buffer_[buffer_size - 1] =
'\0';
4082 inline auto str() const -> std::
string {
return {str_, size()}; }
4085 #define FMTQUILL_STRING_IMPL(s, base) \ 4089 struct FMTQUILL_VISIBILITY("hidden") FMTQUILL_COMPILE_STRING : base { \ 4090 using char_type = fmtquill::remove_cvref_t<decltype(s[0])>; \ 4091 constexpr explicit operator fmtquill::basic_string_view<char_type>() const { \ 4092 return fmtquill::detail::compile_string_to_view<char_type>(s); \ 4095 using FMTQUILL_STRING_VIEW = \ 4096 fmtquill::basic_string_view<typename FMTQUILL_COMPILE_STRING::char_type>; \ 4097 fmtquill::detail::ignore_unused(FMTQUILL_STRING_VIEW(FMTQUILL_COMPILE_STRING())); \ 4098 return FMTQUILL_COMPILE_STRING(); \ 4109 #define FMTQUILL_STRING(s) FMTQUILL_STRING_IMPL(s, fmtquill::detail::compile_string) 4112 -> std::system_error;
4129 template <
typename... T>
4130 auto system_error(
int error_code, format_string<T...> fmt, T&&... args)
4131 -> std::system_error {
4132 return vsystem_error(error_code, fmt.str,
vargs<T...>{{args...}});
4149 const char* message) noexcept;
4153 FMTQUILL_API
void report_system_error(
int error_code,
const char* message) noexcept;
4155 template <typename Locale, FMTQUILL_ENABLE_IF(detail::is_locale<Locale>::value)>
4163 template <
typename Locale,
typename... T,
4165 FMTQUILL_INLINE
auto format(
const Locale& loc, format_string<T...> fmt, T&&... args)
4167 return vformat(loc, fmt.str,
vargs<T...>{{args...}});
4170 template <
typename OutputIt,
typename Locale,
4172 auto vformat_to(OutputIt out,
const Locale& loc,
string_view fmt,
4174 auto&& buf = detail::get_buffer<char>(out);
4176 return detail::get_iterator(buf, out);
4179 template <
typename OutputIt,
typename Locale,
typename... T,
4182 FMTQUILL_INLINE
auto format_to(OutputIt out,
const Locale& loc,
4183 format_string<T...> fmt, T&&... args) -> OutputIt {
4184 return fmtquill::vformat_to(out, loc, fmt.str,
vargs<T...>{{args...}});
4187 template <
typename Locale,
typename... T,
4189 FMTQUILL_NODISCARD FMTQUILL_INLINE
auto formatted_size(
const Locale& loc,
4190 format_string<T...> fmt,
4191 T&&... args) ->
size_t {
4193 detail::vformat_to(buf, fmt.str,
vargs<T...>{{args...}},
4209 template <
typename... T>
4210 FMTQUILL_NODISCARD FMTQUILL_INLINE
auto format(format_string<T...> fmt, T&&... args)
4222 template <typename T, FMTQUILL_ENABLE_IF(std::is_integral<T>::value)>
4223 FMTQUILL_NODISCARD
auto to_string(T value) -> std::string {
4226 char buffer[max_of(detail::digits10<T>() + 2, 5)];
4227 return {buffer, detail::write<char>(buffer, value)};
4230 template <typename T, FMTQUILL_ENABLE_IF(detail::use_format_as<T>::value)>
4231 FMTQUILL_NODISCARD
auto to_string(
const T& value) -> std::string {
4232 return to_string(format_as(value));
4235 template <typename T, FMTQUILL_ENABLE_IF(!std::is_integral<T>::value &&
4237 FMTQUILL_NODISCARD
auto to_string(
const T& value) -> std::string {
4239 detail::write<char>(
appender(buffer), value);
4240 return {buffer.data(), buffer.size()};
4244 FMTQUILL_END_NAMESPACE
4246 #ifdef FMTQUILL_HEADER_ONLY 4247 # define FMTQUILL_FUNC inline 4248 # include "format-inl.h" 4252 #ifdef FMTQUILL_REMOVE_TRANSITIVE_INCLUDES 4253 # undef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES 4256 #if defined(__GNUC__) || defined(__clang__) || defined(__MINGW32__) 4257 #pragma GCC diagnostic pop 4260 #endif // FMTQUILL_FORMAT_H_ Definition: format.h:3904
Definition: format.h:2481
A dynamically growing memory buffer for trivially copyable/constructible types with the first SIZE el...
Definition: format.h:790
FMTQUILL_CONSTEXPR auto data() noexcept -> T *
Returns a pointer to the buffer data (not null-terminated).
Definition: base.h:1799
void reserve(size_t new_capacity)
Increases the buffer capacity to new_capacity.
Definition: format.h:882
Definition: format.h:3876
Definition: format.h:1986
FMTQUILL_CONSTEXPR void set(T *buf_data, size_t buf_capacity) noexcept
Sets the buffer data and capacity.
Definition: base.h:1774
Definition: format.h:2449
Definition: format.h:1834
Definition: format.h:3738
Definition: format.h:2008
Definition: format.h:1965
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition: base.h:644
Definition: LogFunctions.h:198
FMTQUILL_CONSTEXPR void check_arg_id(int id)
Reports an error if using the automatic argument indexing; otherwise switches to the manual indexing...
Definition: base.h:914
Definition: format.h:3670
FMTQUILL_CONSTEXPR20 void append(const U *begin, const U *end)
Appends data to the end of the buffer.
Definition: base.h:1833
constexpr auto data() const noexcept -> const Char *
Returns a pointer to the string data.
Definition: base.h:565
FMTQUILL_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer &&other) noexcept
Constructs a basic_memory_buffer object moving the content of the other object to it...
Definition: format.h:861
Definition: format.h:3525
Definition: format.h:1131
FMTQUILL_CONSTEXPR void advance_to(iterator it)
Advances the begin iterator to it.
Definition: base.h:896
constexpr auto size() const noexcept -> size_t
Returns the string size.
Definition: base.h:568
Definition: format.h:1438
Definition: LogFunctions.h:261
FMTQUILL_CONSTEXPR auto next_arg_id() -> int
Reports an error if using the manual argument indexing; otherwise returns the next argument index and...
Definition: base.h:902
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:24
An implementation of std::basic_string_view for pre-C++17.
Definition: base.h:523
Definition: format.h:1530
FMTQUILL_CONSTEXPR void clear()
Clears this buffer.
Definition: base.h:1803
constexpr auto end() const noexcept -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition: base.h:893
constexpr auto size() const noexcept -> size_t
Returns the size of this buffer.
Definition: base.h:1793
void print(format_string< T... > fmt, T &&... args)
Formats args according to specifications in fmt and writes the output to the file.
Definition: format.h:916
Definition: format.h:1424
Definition: format.h:3946
Definition: format.h:1289
Definition: format.h:2241
constexpr auto capacity() const noexcept -> size_t
Returns the capacity of this buffer.
Definition: base.h:1796
Definition: format.h:1702
Definition: format.h:4006
constexpr auto begin() const noexcept -> iterator
Returns an iterator to the beginning of the format string range being parsed.
Definition: base.h:890
Definition: doctest.h:526
Definition: format.h:2523
Definition: format.h:1272
Definition: format.h:3857
Definition: format.h:3592
A contiguous memory buffer with an optional growing ability.
Definition: base.h:1751
auto operator=(basic_memory_buffer &&other) noexcept -> basic_memory_buffer &
Moves the content of the other basic_memory_buffer object to this one.
Definition: format.h:867
FMTQUILL_CONSTEXPR void resize(size_t count)
Resizes the buffer to contain count elements.
Definition: format.h:879
Definition: format.h:1465