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" 49 #if FMTQUILL_HAS_INCLUDE(<string_view>) && \ 50 (FMTQUILL_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION)) 51 # define FMTQUILL_USE_STRING_VIEW 54 #ifndef FMTQUILL_MODULE 63 # if defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI) 69 # include <system_error> 72 # if FMTQUILL_HAS_INCLUDE(<bit>) && FMTQUILL_CPLUSPLUS > 201703L 76 # if defined(FMTQUILL_USE_STRING_VIEW) 77 # include <string_view> 80 # if FMTQUILL_MSC_VERSION 83 #endif // FMTQUILL_MODULE 85 #if defined(FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS) 87 #elif defined(__NVCOMPILER) 88 # define FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 0 89 #elif FMTQUILL_GCC_VERSION >= 903 && FMTQUILL_CPLUSPLUS >= 201709L 90 # define FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 1 91 #elif defined(__cpp_nontype_template_args) && \ 92 __cpp_nontype_template_args >= 201911L 93 # define FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 1 94 #elif FMTQUILL_CLANG_VERSION >= 1200 && FMTQUILL_CPLUSPLUS >= 202002L 95 # define FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 1 97 # define FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 0 100 #if defined __cpp_inline_variables && __cpp_inline_variables >= 201606L 101 # define FMTQUILL_INLINE_VARIABLE inline 103 # define FMTQUILL_INLINE_VARIABLE 107 #ifdef FMTQUILL_USE_RTTI 109 #elif defined(__GXX_RTTI) || FMTQUILL_HAS_FEATURE(cxx_rtti) || defined(_CPPRTTI) || \ 110 defined(__INTEL_RTTI__) || defined(__RTTI) 112 # define FMTQUILL_USE_RTTI 1 114 # define FMTQUILL_USE_RTTI 0 118 #if defined(FMTQUILL_LIB_EXPORT) || defined(FMTQUILL_SHARED) 119 # define FMTQUILL_SO_VISIBILITY(value) FMTQUILL_VISIBILITY(value) 121 # define FMTQUILL_SO_VISIBILITY(value) 124 #if FMTQUILL_GCC_VERSION || FMTQUILL_CLANG_VERSION 125 # define FMTQUILL_NOINLINE __attribute__((noinline)) 127 # define FMTQUILL_NOINLINE 130 #ifdef FMTQUILL_DEPRECATED 132 #elif FMTQUILL_HAS_CPP14_ATTRIBUTE(deprecated) 133 # define FMTQUILL_DEPRECATED [[deprecated]] 135 # define FMTQUILL_DEPRECATED 139 #if !FMTQUILL_USE_CONSTEVAL 140 # define FMTQUILL_USE_CONSTEXPR_STRING 0 141 #elif defined(__cpp_lib_constexpr_string) && \ 142 __cpp_lib_constexpr_string >= 201907L 143 # if FMTQUILL_CLANG_VERSION && FMTQUILL_GLIBCXX_RELEASE 146 # if FMTQUILL_GLIBCXX_RELEASE < 13 147 # define FMTQUILL_USE_CONSTEXPR_STRING 0 148 # elif FMTQUILL_GLIBCXX_RELEASE == 13 && __GLIBCXX__ < 20240521 149 # define FMTQUILL_USE_CONSTEXPR_STRING 0 151 # define FMTQUILL_USE_CONSTEXPR_STRING 1 154 # define FMTQUILL_USE_CONSTEXPR_STRING 1 157 # define FMTQUILL_USE_CONSTEXPR_STRING 0 159 #if FMTQUILL_USE_CONSTEXPR_STRING 160 # define FMTQUILL_CONSTEXPR_STRING constexpr 162 # define FMTQUILL_CONSTEXPR_STRING 168 using iterator_category = output_iterator_tag;
169 using value_type = T;
170 using difference_type =
171 decltype(static_cast<int*>(
nullptr) - static_cast<int*>(
nullptr));
172 using pointer = void;
173 using reference = void;
177 #ifdef FMTQUILL_THROW 179 #elif FMTQUILL_USE_EXCEPTIONS 180 # define FMTQUILL_THROW(x) throw x 182 # define FMTQUILL_THROW(x) ::fmtquill::assert_fail(__FILE__, __LINE__, (x).what()) 185 #ifdef __clang_analyzer__ 186 # define FMTQUILL_CLANG_ANALYZER 1 188 # define FMTQUILL_CLANG_ANALYZER 0 195 #if !defined(FMTQUILL_REDUCE_INT_INSTANTIATIONS) 196 # define FMTQUILL_REDUCE_INT_INSTANTIATIONS 0 199 FMTQUILL_BEGIN_NAMESPACE
201 template <
typename Char,
typename Traits,
typename Allocator>
209 #if !FMTQUILL_MSC_VERSION 210 # if FMTQUILL_HAS_BUILTIN(__builtin_clz) || FMTQUILL_GCC_VERSION || FMTQUILL_ICC_VERSION 211 # define FMTQUILL_BUILTIN_CLZ(n) __builtin_clz(n) 213 # if FMTQUILL_HAS_BUILTIN(__builtin_clzll) || FMTQUILL_GCC_VERSION || FMTQUILL_ICC_VERSION 214 # define FMTQUILL_BUILTIN_CLZLL(n) __builtin_clzll(n) 221 #if FMTQUILL_MSC_VERSION && !defined(FMTQUILL_BUILTIN_CLZLL) 224 # pragma intrinsic(_BitScanReverse) 226 # pragma intrinsic(_BitScanReverse64) 230 inline auto clz(uint32_t x) ->
int {
231 FMTQUILL_ASSERT(x != 0,
"");
232 FMTQUILL_MSC_WARNING(suppress : 6102)
234 _BitScanReverse(&r, x);
235 return 31 ^
static_cast<int>(r);
237 # define FMTQUILL_BUILTIN_CLZ(n) detail::clz(n) 239 inline auto clzll(uint64_t x) ->
int {
240 FMTQUILL_ASSERT(x != 0,
"");
241 FMTQUILL_MSC_WARNING(suppress : 6102)
244 _BitScanReverse64(&r, x);
247 if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
248 return 63 ^
static_cast<int>(r + 32);
250 _BitScanReverse(&r, static_cast<uint32_t>(x));
252 return 63 ^
static_cast<int>(r);
254 # define FMTQUILL_BUILTIN_CLZLL(n) detail::clzll(n) 255 #endif // FMTQUILL_MSC_VERSION && !defined(FMTQUILL_BUILTIN_CLZLL) 257 FMTQUILL_CONSTEXPR
inline void abort_fuzzing_if(
bool condition) {
258 ignore_unused(condition);
260 if (condition)
throw std::runtime_error(
"fuzzing limit reached");
264 #if defined(FMTQUILL_USE_STRING_VIEW) 265 template <
typename Char>
using std_string_view = std::basic_string_view<Char>;
273 static constexpr Char
value[
sizeof...(C)] = {C...};
275 return {
value,
sizeof...(C)};
278 #if FMTQUILL_CPLUSPLUS < 201703L 279 template <
typename Char, Char... C>
284 template <
typename To,
typename From, FMTQUILL_ENABLE_IF(sizeof(To) == sizeof(From))>
285 FMTQUILL_CONSTEXPR20
auto bit_cast(
const From& from) -> To {
286 #ifdef __cpp_lib_bit_cast 287 if (is_constant_evaluated())
return std::bit_cast<To>(from);
291 std::memcpy(static_cast<void*>(&to), &from,
sizeof(to));
295 inline auto is_big_endian() ->
bool {
298 #elif defined(__BIG_ENDIAN__) 300 #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) 301 return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;
304 char data[
sizeof(int)];
306 return bit_cast<
bytes>(1).data[0] == 0;
316 constexpr uint128_fallback(uint64_t
value = 0) : lo_(
value), hi_(0) {}
318 constexpr
auto high()
const noexcept -> uint64_t {
return hi_; }
319 constexpr
auto low()
const noexcept -> uint64_t {
return lo_; }
321 template <typename T, FMTQUILL_ENABLE_IF(std::is_integral<T>::value)>
322 constexpr
explicit operator T()
const {
323 return static_cast<T
>(lo_);
326 friend constexpr
auto operator==(
const uint128_fallback& lhs,
327 const uint128_fallback& rhs) ->
bool {
328 return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_;
330 friend constexpr
auto operator!=(
const uint128_fallback& lhs,
331 const uint128_fallback& rhs) ->
bool {
332 return !(lhs == rhs);
334 friend constexpr
auto operator>(
const uint128_fallback& lhs,
335 const uint128_fallback& rhs) ->
bool {
336 return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_;
338 friend constexpr
auto operator|(
const uint128_fallback& lhs,
339 const uint128_fallback& rhs)
340 -> uint128_fallback {
341 return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_};
343 friend constexpr
auto operator&(
const uint128_fallback& lhs,
344 const uint128_fallback& rhs)
345 -> uint128_fallback {
346 return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_};
348 friend constexpr
auto operator~(
const uint128_fallback& n)
349 -> uint128_fallback {
350 return {~n.hi_, ~n.lo_};
352 friend FMTQUILL_CONSTEXPR
auto operator+(
const uint128_fallback& lhs,
353 const uint128_fallback& rhs)
354 -> uint128_fallback {
355 auto result = uint128_fallback(lhs);
359 friend FMTQUILL_CONSTEXPR
auto operator*(
const uint128_fallback& lhs, uint32_t rhs)
360 -> uint128_fallback {
361 FMTQUILL_ASSERT(lhs.hi_ == 0,
"");
362 uint64_t hi = (lhs.lo_ >> 32) * rhs;
363 uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs;
364 uint64_t new_lo = (hi << 32) + lo;
365 return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo};
367 friend constexpr
auto operator-(
const uint128_fallback& lhs, uint64_t rhs)
368 -> uint128_fallback {
369 return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs};
371 FMTQUILL_CONSTEXPR
auto operator>>(
int shift)
const -> uint128_fallback {
372 if (shift == 64)
return {0, hi_};
373 if (shift > 64)
return uint128_fallback(0, hi_) >> (shift - 64);
374 return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)};
376 FMTQUILL_CONSTEXPR
auto operator<<(
int shift)
const -> uint128_fallback {
377 if (shift == 64)
return {lo_, 0};
378 if (shift > 64)
return uint128_fallback(lo_, 0) << (shift - 64);
379 return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)};
381 FMTQUILL_CONSTEXPR
auto operator>>=(
int shift) -> uint128_fallback& {
382 return *
this = *
this >> shift;
384 FMTQUILL_CONSTEXPR
void operator+=(uint128_fallback n) {
385 uint64_t new_lo = lo_ + n.lo_;
386 uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0);
387 FMTQUILL_ASSERT(new_hi >= hi_,
"");
391 FMTQUILL_CONSTEXPR
void operator&=(uint128_fallback n) {
396 FMTQUILL_CONSTEXPR20
auto operator+=(uint64_t n) noexcept -> uint128_fallback& {
397 if (is_constant_evaluated()) {
399 hi_ += (lo_ < n ? 1 : 0);
402 #if FMTQUILL_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__) 403 unsigned long long carry;
404 lo_ = __builtin_addcll(lo_, n, 0, &carry);
406 #elif FMTQUILL_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__) 407 unsigned long long result;
408 auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result);
411 #elif defined(_MSC_VER) && defined(_M_X64) 412 auto carry = _addcarry_u64(0, lo_, n, &lo_);
413 _addcarry_u64(carry, hi_, 0, &hi_);
416 hi_ += (lo_ < n ? 1 : 0);
422 using uint128_t = conditional_t<FMTQUILL_USE_INT128, uint128_opt, uint128_fallback>;
425 using uintptr_t = ::uintptr_t;
427 using uintptr_t = uint128_t;
432 template <
typename T> constexpr
auto max_value() -> T {
433 return (std::numeric_limits<T>::max)();
435 template <
typename T> constexpr
auto num_bits() ->
int {
436 return std::numeric_limits<T>::digits;
439 template <> constexpr
auto num_bits<int128_opt>() ->
int {
return 128; }
440 template <> constexpr
auto num_bits<uint128_opt>() ->
int {
return 128; }
441 template <> constexpr
auto num_bits<uint128_fallback>() ->
int {
return 128; }
445 template <
typename To,
typename From, FMTQUILL_ENABLE_IF(sizeof(To) >
sizeof(From))>
446 inline auto bit_cast(
const From& from) -> To {
447 constexpr
auto size =
static_cast<int>(
sizeof(From) /
sizeof(
unsigned short));
449 unsigned short value[
static_cast<unsigned>(size)];
450 } data = bit_cast<data_t>(from);
452 if (const_check(is_big_endian())) {
453 for (
int i = 0; i < size; ++i)
454 result = (result << num_bits<unsigned short>()) | data.value[i];
456 for (
int i = size - 1; i >= 0; --i)
457 result = (result << num_bits<unsigned short>()) | data.value[i];
462 template <
typename UInt>
463 FMTQUILL_CONSTEXPR20
inline auto countl_zero_fallback(UInt n) ->
int {
465 constexpr UInt msb_mask =
static_cast<UInt
>(1) << (num_bits<UInt>() - 1);
466 for (; (n & msb_mask) == 0; n <<= 1) lz++;
470 FMTQUILL_CONSTEXPR20
inline auto countl_zero(uint32_t n) ->
int {
471 #ifdef FMTQUILL_BUILTIN_CLZ 472 if (!is_constant_evaluated())
return FMTQUILL_BUILTIN_CLZ(n);
474 return countl_zero_fallback(n);
477 FMTQUILL_CONSTEXPR20
inline auto countl_zero(uint64_t n) ->
int {
478 #ifdef FMTQUILL_BUILTIN_CLZLL 479 if (!is_constant_evaluated())
return FMTQUILL_BUILTIN_CLZLL(n);
481 return countl_zero_fallback(n);
484 FMTQUILL_INLINE
void assume(
bool condition) {
486 #if FMTQUILL_HAS_BUILTIN(__builtin_assume) && !FMTQUILL_ICC_VERSION 487 __builtin_assume(condition);
488 #elif FMTQUILL_GCC_VERSION 489 if (!condition) __builtin_unreachable();
495 template <
typename OutputIt,
498 #if FMTQUILL_CLANG_VERSION >= 307 && !FMTQUILL_ICC_VERSION 499 __attribute__((no_sanitize(
"undefined")))
501 FMTQUILL_CONSTEXPR20
inline auto 502 reserve(OutputIt it,
size_t n) ->
typename OutputIt::value_type* {
503 auto& c = get_container(it);
504 size_t size = c.size();
509 template <
typename T>
513 buf.try_reserve(buf.
size() + n);
517 template <
typename Iterator>
518 constexpr
auto reserve(Iterator& it,
size_t) -> Iterator& {
522 template <
typename OutputIt>
523 using reserve_iterator =
524 remove_reference_t<decltype(reserve(std::declval<OutputIt&>(), 0))>;
526 template <
typename T,
typename OutputIt>
527 constexpr
auto to_pointer(OutputIt,
size_t) -> T* {
530 template <
typename T> FMTQUILL_CONSTEXPR
auto to_pointer(T*& ptr,
size_t n) -> T* {
535 template <
typename T>
538 buf.try_reserve(buf.
size() + n);
539 auto size = buf.
size();
540 if (buf.
capacity() < size + n)
return nullptr;
541 buf.try_resize(size + n);
542 return buf.
data() + size;
545 template <
typename OutputIt,
548 inline auto base_iterator(OutputIt it,
549 typename OutputIt::container_type::value_type*)
554 template <
typename Iterator>
555 constexpr
auto base_iterator(Iterator, Iterator it) -> Iterator {
561 template <
typename OutputIt,
typename Size,
typename T>
562 FMTQUILL_CONSTEXPR
auto fill_n(OutputIt out, Size count,
const T&
value)
564 for (Size i = 0; i < count; ++i) *out++ = value;
567 template <
typename T,
typename Size>
568 FMTQUILL_CONSTEXPR20
auto fill_n(T* out, Size count,
char value) -> T* {
569 if (is_constant_evaluated())
return fill_n<T*, Size, T>(out, count, value);
570 static_assert(
sizeof(T) == 1,
571 "sizeof(T) must be 1 to use char for initialization");
572 std::memset(out, value, to_unsigned(count));
576 template <
typename OutChar,
typename InputIt,
typename OutputIt>
577 FMTQUILL_CONSTEXPR FMTQUILL_NOINLINE
auto copy_noinline(InputIt begin, InputIt end,
578 OutputIt out) -> OutputIt {
579 return copy<OutChar>(begin, end, out);
599 FMTQUILL_CONSTEXPR
inline auto utf8_decode(
const char* s, uint32_t* c,
int* e)
601 constexpr
int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
602 constexpr uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
603 constexpr
int shiftc[] = {0, 18, 12, 6, 0};
604 constexpr
int shifte[] = {0, 6, 4, 2, 0};
606 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" 607 [
static_cast<unsigned char>(*s) >> 3];
611 const char* next = s + len + !len;
613 using uchar =
unsigned char;
617 *c = uint32_t(uchar(s[0]) & masks[len]) << 18;
618 *c |= uint32_t(uchar(s[1]) & 0x3f) << 12;
619 *c |= uint32_t(uchar(s[2]) & 0x3f) << 6;
620 *c |= uint32_t(uchar(s[3]) & 0x3f) << 0;
624 *e = (*c < mins[len]) << 6;
625 *e |= ((*c >> 11) == 0x1b) << 7;
626 *e |= (*c > 0x10FFFF) << 8;
627 *e |= (uchar(s[1]) & 0xc0) >> 2;
628 *e |= (uchar(s[2]) & 0xc0) >> 4;
629 *e |= uchar(s[3]) >> 6;
636 constexpr FMTQUILL_INLINE_VARIABLE uint32_t invalid_code_point = ~uint32_t();
640 template <
typename F>
641 FMTQUILL_CONSTEXPR
void for_each_codepoint(
string_view s, F f) {
642 auto decode = [f](
const char* buf_ptr,
const char* ptr) {
643 auto cp = uint32_t();
645 auto end = utf8_decode(buf_ptr, &cp, &
error);
646 bool result = f(
error ? invalid_code_point : cp,
648 return result ? (
error ? buf_ptr + 1 : end) :
nullptr;
652 const size_t block_size = 4;
653 if (s.
size() >= block_size) {
654 for (
auto end = p + s.
size() - block_size + 1; p < end;) {
659 auto num_chars_left = to_unsigned(s.
data() + s.
size() - p);
660 if (num_chars_left == 0)
return;
663 if (FMTQUILL_GCC_VERSION) num_chars_left &= 3;
664 #if defined(__GNUC__) && !defined(__clang__) 665 #pragma GCC diagnostic push 666 #pragma GCC diagnostic ignored "-Wstringop-overflow" 668 char buf[2 * block_size - 1] = {};
669 #if defined(__GNUC__) && !defined(__clang__) 670 #pragma GCC diagnostic pop 672 copy<char>(p, p + num_chars_left, buf);
673 const char* buf_ptr = buf;
675 auto end = decode(buf_ptr, p);
679 }
while (buf_ptr < buf + num_chars_left);
682 FMTQUILL_CONSTEXPR
inline auto display_width_of(uint32_t cp) noexcept ->
size_t {
689 (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) ||
690 (cp >= 0xac00 && cp <= 0xd7a3) ||
691 (cp >= 0xf900 && cp <= 0xfaff) ||
692 (cp >= 0xfe10 && cp <= 0xfe19) ||
693 (cp >= 0xfe30 && cp <= 0xfe6f) ||
694 (cp >= 0xff00 && cp <= 0xff60) ||
695 (cp >= 0xffe0 && cp <= 0xffe6) ||
696 (cp >= 0x20000 && cp <= 0x2fffd) ||
697 (cp >= 0x30000 && cp <= 0x3fffd) ||
699 (cp >= 0x1f300 && cp <= 0x1f64f) ||
701 (cp >= 0x1f900 && cp <= 0x1f9ff))));
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>
742 sizeof(T) <= sizeof(double)> {};
743 template <typename T> struct is_fast_float<T, false> : std::false_type {};
745 template <typename T>
746 using fast_float_t = conditional_t<sizeof(T) == sizeof(double), double, float>;
748 template <typename T>
749 using is_double_double = bool_constant<std::numeric_limits<T>::digits == 106>;
751 #ifndef FMTQUILL_USE_FULL_CACHE_DRAGONBOX
752 # define FMTQUILL_USE_FULL_CACHE_DRAGONBOX 0
758 template <typename T> struct allocator : private std::decay<void> {
759 using value_type = T;
761 auto allocate(size_t n) -> T* {
762 FMTQUILL_ASSERT(n <= max_value<size_t>() /
sizeof(T),
"");
763 T* p =
static_cast<T*
>(malloc(n *
sizeof(T)));
764 if (!p) FMTQUILL_THROW(std::bad_alloc());
768 void deallocate(T* p,
size_t) { free(p); }
770 constexpr
friend auto operator==(allocator, allocator) noexcept ->
bool {
773 constexpr
friend auto operator!=(allocator, allocator) noexcept ->
bool {
778 template <
typename Formatter>
779 FMTQUILL_CONSTEXPR
auto maybe_set_debug_format(Formatter& f,
bool set)
780 -> decltype(f.set_debug_format(
set)) {
781 f.set_debug_format(
set);
783 template <
typename Formatter>
784 FMTQUILL_CONSTEXPR
void maybe_set_debug_format(Formatter&, ...) {}
788 FMTQUILL_BEGIN_EXPORT
792 enum { inline_buffer_size = 500 };
807 template <
typename T,
size_t SIZE = inline_buffer_size,
808 typename Allocator = detail::allocator<T>>
814 FMTQUILL_NO_UNIQUE_ADDRESS Allocator alloc_;
817 FMTQUILL_CONSTEXPR20
void deallocate() {
818 T* data = this->data();
819 if (data != store_) alloc_.deallocate(data, this->capacity());
823 detail::abort_fuzzing_if(size > 5000);
825 const size_t max_size =
826 std::allocator_traits<Allocator>::max_size(
self.alloc_);
827 size_t old_capacity = buf.
capacity();
828 size_t new_capacity = old_capacity + old_capacity / 2;
829 if (size > new_capacity)
831 else if (new_capacity > max_size)
832 new_capacity = max_of(size, max_size);
833 T* old_data = buf.
data();
834 T* new_data =
self.alloc_.allocate(new_capacity);
836 detail::assume(buf.
size() <= new_capacity);
838 memcpy(new_data, old_data, buf.
size() *
sizeof(T));
839 self.set(new_data, new_capacity);
843 if (old_data !=
self.store_)
self.alloc_.deallocate(old_data, old_capacity);
847 using value_type = T;
848 using const_reference =
const T&;
851 const Allocator& alloc = Allocator())
853 this->
set(store_, SIZE);
854 if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T());
856 FMTQUILL_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); }
859 template <
typename Alloc = Allocator,
860 FMTQUILL_ENABLE_IF(std::allocator_traits<Alloc>::
861 propagate_on_container_move_assignment::value)>
862 FMTQUILL_CONSTEXPR20
auto move_alloc(basic_memory_buffer& other) ->
bool {
863 alloc_ = std::move(other.alloc_);
867 template <
typename Alloc = Allocator,
868 FMTQUILL_ENABLE_IF(!std::allocator_traits<Alloc>::
869 propagate_on_container_move_assignment::value)>
870 FMTQUILL_CONSTEXPR20
auto move_alloc(basic_memory_buffer& other) ->
bool {
871 T* data = other.
data();
872 if (alloc_ == other.alloc_ || data == other.store_)
return true;
873 size_t size = other.
size();
876 detail::copy<T>(data, data + size, this->data());
881 FMTQUILL_CONSTEXPR20
void move(basic_memory_buffer& other) {
882 T* data = other.
data();
883 size_t size = other.
size(), capacity = other.
capacity();
884 if (!move_alloc(other))
return;
885 if (data == other.store_) {
886 this->
set(store_, capacity);
887 detail::copy<T>(other.store_, other.store_ + size, store_);
889 this->
set(data, capacity);
892 other.
set(other.store_, 0);
907 auto operator=(basic_memory_buffer&& other) noexcept -> basic_memory_buffer& {
908 FMTQUILL_ASSERT(
this != &other,
"");
915 auto get_allocator()
const -> Allocator {
return alloc_; }
919 FMTQUILL_CONSTEXPR
void resize(
size_t count) { this->try_resize(count); }
922 void reserve(
size_t new_capacity) { this->try_reserve(new_capacity); }
925 template <
typename ContiguousRange>
926 FMTQUILL_CONSTEXPR20
void append(
const ContiguousRange& range) {
927 append(range.data(), range.data() + range.size());
933 template <
size_t SIZE>
936 auto size = buf.
size();
937 detail::assume(size < std::string().max_size());
938 return {buf.
data(), size};
951 inline writer(FILE* f) : buf_(
nullptr), file_(f) {}
956 template <
typename... T>
void print(format_string<T...> fmt, T&&... args) {
958 fmtquill::format_to(
appender(*buf_), fmt, std::forward<T>(args)...);
960 fmtquill::print(file_, fmt, std::forward<T>(args)...);
972 inline operator writer() {
return buf_; }
973 inline auto str() -> std::string& {
return str_; }
976 template <
typename T,
size_t SIZE,
typename Allocator>
981 FMTQUILL_PRAGMA_CLANG(diagnostic ignored
"-Wweak-vtables")
983 class FMTQUILL_SO_VISIBILITY("default") format_error :
public std::runtime_error {
986 using std::runtime_error::runtime_error;
993 FMTQUILL_API
auto write_console(
int fd,
string_view text) -> bool;
1000 detail::copy<Char, const Char*, Char*>(
static_cast<const Char*
>(s), s + N,
1007 FMTQUILL_EXPORT
template <
typename Char,
size_t N>
1008 constexpr
auto compile_string_to_view(
const Char (&s)[N])
1014 FMTQUILL_EXPORT
template <
typename Char>
1022 template <typename T, FMTQUILL_ENABLE_IF(is_signed<T>::value)>
1023 constexpr
auto is_negative(T
value) ->
bool {
1026 template <typename T, FMTQUILL_ENABLE_IF(!is_signed<T>::value)>
1027 constexpr
auto is_negative(T) ->
bool {
1033 template <
typename T>
1034 using uint32_or_64_or_128_t =
1035 conditional_t<num_bits<T>() <= 32 && !FMTQUILL_REDUCE_INT_INSTANTIATIONS,
1037 conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>;
1038 template <
typename T>
1039 using uint64_or_128_t = conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>;
1041 #define FMTQUILL_POWERS_OF_10(factor) \ 1042 factor * 10, (factor) * 100, (factor) * 1000, (factor) * 10000, \ 1043 (factor) * 100000, (factor) * 1000000, (factor) * 10000000, \ 1044 (factor) * 100000000, (factor) * 1000000000 1048 inline auto digits2(
size_t value) ->
const char* {
1051 alignas(2)
static const char data[] =
1052 "0001020304050607080910111213141516171819" 1053 "2021222324252627282930313233343536373839" 1054 "4041424344454647484950515253545556575859" 1055 "6061626364656667686970717273747576777879" 1056 "8081828384858687888990919293949596979899";
1057 return &data[value * 2];
1060 template <
typename Char> constexpr
auto getsign(sign s) -> Char {
1061 return static_cast<char>(((
' ' << 24) | (
'+' << 16) | (
'-' << 8)) >>
1062 (
static_cast<int>(s) * 8));
1065 template <
typename T> FMTQUILL_CONSTEXPR
auto count_digits_fallback(T n) ->
int {
1071 if (n < 10)
return count;
1072 if (n < 100)
return count + 1;
1073 if (n < 1000)
return count + 2;
1074 if (n < 10000)
return count + 3;
1079 #if FMTQUILL_USE_INT128 1080 FMTQUILL_CONSTEXPR
inline auto count_digits(uint128_opt n) ->
int {
1081 return count_digits_fallback(n);
1085 #ifdef FMTQUILL_BUILTIN_CLZLL 1088 inline auto do_count_digits(uint64_t n) ->
int {
1093 static constexpr uint8_t bsr2log10[] = {
1094 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
1095 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
1096 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
1097 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20};
1098 auto t = bsr2log10[FMTQUILL_BUILTIN_CLZLL(n | 1) ^ 63];
1099 static constexpr uint64_t zero_or_powers_of_10[] = {
1100 0, 0, FMTQUILL_POWERS_OF_10(1U), FMTQUILL_POWERS_OF_10(1000000000ULL),
1101 10000000000000000000ULL};
1102 return t - (n < zero_or_powers_of_10[t]);
1108 FMTQUILL_CONSTEXPR20
inline auto count_digits(uint64_t n) ->
int {
1109 #ifdef FMTQUILL_BUILTIN_CLZLL 1110 if (!is_constant_evaluated() && !FMTQUILL_OPTIMIZE_SIZE)
return do_count_digits(n);
1112 return count_digits_fallback(n);
1116 template <
int BITS,
typename UInt>
1117 FMTQUILL_CONSTEXPR
auto count_digits(UInt n) ->
int {
1118 #ifdef FMTQUILL_BUILTIN_CLZ 1119 if (!is_constant_evaluated() && num_bits<UInt>() == 32)
1120 return (FMTQUILL_BUILTIN_CLZ(static_cast<uint32_t>(n) | 1) ^ 31) / BITS + 1;
1127 }
while ((m >>= BITS) != 0);
1132 #ifdef FMTQUILL_BUILTIN_CLZ 1135 FMTQUILL_INLINE
auto do_count_digits(uint32_t n) ->
int {
1138 # define FMTQUILL_INC(T) (((sizeof(#T) - 1ull) << 32) - T) 1139 static constexpr uint64_t table[] = {
1140 FMTQUILL_INC(0), FMTQUILL_INC(0), FMTQUILL_INC(0),
1141 FMTQUILL_INC(10), FMTQUILL_INC(10), FMTQUILL_INC(10),
1142 FMTQUILL_INC(100), FMTQUILL_INC(100), FMTQUILL_INC(100),
1143 FMTQUILL_INC(1000), FMTQUILL_INC(1000), FMTQUILL_INC(1000),
1144 FMTQUILL_INC(10000), FMTQUILL_INC(10000), FMTQUILL_INC(10000),
1145 FMTQUILL_INC(100000), FMTQUILL_INC(100000), FMTQUILL_INC(100000),
1146 FMTQUILL_INC(1000000), FMTQUILL_INC(1000000), FMTQUILL_INC(1000000),
1147 FMTQUILL_INC(10000000), FMTQUILL_INC(10000000), FMTQUILL_INC(10000000),
1148 FMTQUILL_INC(100000000), FMTQUILL_INC(100000000), FMTQUILL_INC(100000000),
1149 FMTQUILL_INC(1000000000), FMTQUILL_INC(1000000000), FMTQUILL_INC(1000000000),
1150 FMTQUILL_INC(1000000000), FMTQUILL_INC(1000000000)
1152 auto inc = table[FMTQUILL_BUILTIN_CLZ(n | 1) ^ 31];
1153 return static_cast<int>((n + inc) >> 32);
1158 FMTQUILL_CONSTEXPR20
inline auto count_digits(uint32_t n) ->
int {
1159 #ifdef FMTQUILL_BUILTIN_CLZ 1160 if (!is_constant_evaluated() && !FMTQUILL_OPTIMIZE_SIZE)
return do_count_digits(n);
1162 return count_digits_fallback(n);
1165 template <
typename Int> constexpr
auto digits10() noexcept ->
int {
1166 return std::numeric_limits<Int>::digits10;
1168 template <> constexpr
auto digits10<int128_opt>() noexcept ->
int {
return 38; }
1169 template <> constexpr
auto digits10<uint128_t>() noexcept ->
int {
return 38; }
1172 std::string grouping;
1176 template <
typename Char>
1178 template <
typename Char>
1180 auto result = thousands_sep_impl<char>(loc);
1181 return {result.grouping, Char(result.thousands_sep)};
1185 return thousands_sep_impl<wchar_t>(loc);
1188 template <
typename Char>
1189 FMTQUILL_API
auto decimal_point_impl(
locale_ref loc) -> Char;
1190 template <
typename Char>
inline auto decimal_point(
locale_ref loc) -> Char {
1191 return Char(decimal_point_impl<char>(loc));
1193 template <>
inline auto decimal_point(
locale_ref loc) ->
wchar_t {
1194 return decimal_point_impl<wchar_t>(loc);
1197 #ifndef FMTQUILL_HEADER_ONLY 1198 FMTQUILL_BEGIN_EXPORT
1199 extern template FMTQUILL_API
auto thousands_sep_impl<char>(
locale_ref)
1201 extern template FMTQUILL_API
auto thousands_sep_impl<wchar_t>(
locale_ref)
1203 extern template FMTQUILL_API
auto decimal_point_impl(
locale_ref) -> char;
1204 extern template FMTQUILL_API
auto decimal_point_impl(
locale_ref) -> wchar_t;
1206 #endif // FMTQUILL_HEADER_ONLY 1209 template <
typename Char>
auto equal2(
const Char* lhs,
const char* rhs) ->
bool {
1210 return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]);
1212 inline auto equal2(
const char* lhs,
const char* rhs) ->
bool {
1213 return memcmp(lhs, rhs, 2) == 0;
1217 template <
typename Char>
1218 FMTQUILL_CONSTEXPR20 FMTQUILL_INLINE
void write2digits(Char* out,
size_t value) {
1219 if (!is_constant_evaluated() && std::is_same<Char, char>::value &&
1220 !FMTQUILL_OPTIMIZE_SIZE) {
1221 memcpy(out, digits2(value), 2);
1224 *out++ =
static_cast<Char
>(
'0' + value / 10);
1225 *out =
static_cast<Char
>(
'0' + value % 10);
1230 template <
typename Char,
typename UInt>
1231 FMTQUILL_CONSTEXPR20
auto do_format_decimal(Char* out, UInt value,
int size)
1233 FMTQUILL_ASSERT(size >= count_digits(value),
"invalid digit count");
1234 unsigned n = to_unsigned(size);
1235 while (value >= 100) {
1240 write2digits(out + n, static_cast<unsigned>(value % 100));
1245 write2digits(out + n, static_cast<unsigned>(value));
1247 out[--n] =
static_cast<Char
>(
'0' + value);
1252 template <
typename Char,
typename UInt>
1253 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
auto format_decimal(Char* out, UInt value,
1254 int num_digits) -> Char* {
1255 do_format_decimal(out, value, num_digits);
1256 return out + num_digits;
1259 template <
typename Char,
typename UInt,
typename OutputIt,
1260 FMTQUILL_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)>
1261 FMTQUILL_CONSTEXPR
auto format_decimal(OutputIt out, UInt value,
int num_digits)
1263 if (
auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
1264 do_format_decimal(ptr, value, num_digits);
1268 char buffer[digits10<UInt>() + 1];
1269 if (is_constant_evaluated()) fill_n(
buffer,
sizeof(
buffer),
'\0');
1270 do_format_decimal(
buffer, value, num_digits);
1271 return copy_noinline<Char>(
buffer, buffer + num_digits, out);
1274 template <
typename Char,
typename UInt>
1275 FMTQUILL_CONSTEXPR
auto do_format_base2e(
int base_bits, Char* out, UInt value,
1276 int size,
bool upper =
false) -> Char* {
1279 const char* digits = upper ?
"0123456789ABCDEF" :
"0123456789abcdef";
1280 unsigned digit =
static_cast<unsigned>(value & ((1u << base_bits) - 1));
1281 *--out =
static_cast<Char
>(base_bits < 4 ? static_cast<char>(
'0' + digit)
1283 }
while ((value >>= base_bits) != 0);
1288 template <
typename Char,
typename UInt>
1289 FMTQUILL_CONSTEXPR
auto format_base2e(
int base_bits, Char* out, UInt value,
1290 int num_digits,
bool upper =
false) -> Char* {
1291 do_format_base2e(base_bits, out, value, num_digits, upper);
1292 return out + num_digits;
1295 template <
typename Char,
typename OutputIt,
typename UInt,
1297 FMTQUILL_CONSTEXPR
inline auto format_base2e(
int base_bits, OutputIt out, UInt value,
1298 int num_digits,
bool upper =
false)
1300 if (
auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
1301 format_base2e(base_bits, ptr, value, num_digits, upper);
1305 char buffer[num_bits<UInt>()];
1306 if (is_constant_evaluated()) fill_n(
buffer,
sizeof(
buffer),
'\0');
1307 format_base2e(base_bits,
buffer, value, num_digits, upper);
1308 return detail::copy_noinline<Char>(
buffer, buffer + num_digits, out);
1319 return {&buffer_[0], size()};
1321 inline auto size()
const ->
size_t {
return buffer_.
size() - 1; }
1322 inline auto c_str()
const ->
const wchar_t* {
return &buffer_[0]; }
1323 inline auto str()
const -> std::wstring {
return {&buffer_[0], size()}; }
1326 enum class to_utf8_error_policy { abort, replace };
1329 template <
typename WChar,
typename Buffer = memory_buffer>
class to_utf8 {
1336 to_utf8_error_policy policy = to_utf8_error_policy::abort) {
1337 static_assert(
sizeof(WChar) == 2 ||
sizeof(WChar) == 4,
1338 "expected utf16 or utf32");
1339 if (!convert(s, policy)) {
1340 FMTQUILL_THROW(std::runtime_error(
sizeof(WChar) == 2 ?
"invalid utf16" 1341 :
"invalid utf32"));
1345 auto size()
const ->
size_t {
return buffer_.size() - 1; }
1346 auto c_str()
const ->
const char* {
return &buffer_[0]; }
1347 auto str()
const -> std::string {
return std::string(&buffer_[0], size()); }
1353 to_utf8_error_policy policy = to_utf8_error_policy::abort)
1355 if (!convert(buffer_, s, policy))
return false;
1356 buffer_.push_back(0);
1360 to_utf8_error_policy policy = to_utf8_error_policy::abort)
1362 for (
auto p = s.begin(); p != s.end(); ++p) {
1363 uint32_t c =
static_cast<uint32_t
>(*p);
1364 if (
sizeof(WChar) == 2 && c >= 0xd800 && c <= 0xdfff) {
1367 if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) {
1368 if (policy == to_utf8_error_policy::abort)
return false;
1373 c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;
1376 buf.push_back(static_cast<char>(c));
1377 }
else if (c < 0x800) {
1378 buf.push_back(static_cast<char>(0xc0 | (c >> 6)));
1379 buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
1380 }
else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
1381 buf.push_back(static_cast<char>(0xe0 | (c >> 12)));
1382 buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
1383 buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
1384 }
else if (c >= 0x10000 && c <= 0x10ffff) {
1385 buf.push_back(static_cast<char>(0xf0 | (c >> 18)));
1386 buf.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
1387 buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
1388 buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
1398 FMTQUILL_INLINE
auto umul128(uint64_t x, uint64_t y) noexcept ->
uint128_fallback {
1399 #if FMTQUILL_USE_INT128 1400 auto p =
static_cast<uint128_opt
>(x) * static_cast<uint128_opt>(y);
1401 return {
static_cast<uint64_t
>(p >> 64), static_cast<uint64_t>(p)};
1402 #elif defined(_MSC_VER) && defined(_M_X64) 1403 auto hi = uint64_t();
1404 auto lo = _umul128(x, y, &hi);
1407 const uint64_t mask =
static_cast<uint64_t
>(max_value<uint32_t>());
1409 uint64_t a = x >> 32;
1410 uint64_t b = x & mask;
1411 uint64_t c = y >> 32;
1412 uint64_t d = y & mask;
1414 uint64_t ac = a * c;
1415 uint64_t bc = b * c;
1416 uint64_t ad = a * d;
1417 uint64_t bd = b * d;
1419 uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask);
1421 return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32),
1422 (intermediate << 32) + (bd & mask)};
1426 namespace dragonbox {
1429 inline auto floor_log10_pow2(
int e) noexcept ->
int {
1430 FMTQUILL_ASSERT(e <= 2620 && e >= -2620,
"too large exponent");
1431 static_assert((-1 >> 1) == -1,
"right shift is not arithmetic");
1432 return (e * 315653) >> 20;
1435 inline auto floor_log2_pow10(
int e) noexcept ->
int {
1436 FMTQUILL_ASSERT(e <= 1233 && e >= -1233,
"too large exponent");
1437 return (e * 1741647) >> 19;
1441 inline auto umul128_upper64(uint64_t x, uint64_t y) noexcept -> uint64_t {
1442 #if FMTQUILL_USE_INT128 1443 auto p =
static_cast<uint128_opt
>(x) * static_cast<uint128_opt>(y);
1444 return static_cast<uint64_t
>(p >> 64);
1445 #elif defined(_MSC_VER) && defined(_M_X64) 1446 return __umulh(x, y);
1448 return umul128(x, y).high();
1457 r += umul128_upper64(x, y.low());
1467 using carrier_uint = uint32_t;
1468 static const int exponent_bits = 8;
1469 static const int kappa = 1;
1470 static const int big_divisor = 100;
1471 static const int small_divisor = 10;
1472 static const int min_k = -31;
1473 static const int max_k = 46;
1474 static const int shorter_interval_tie_lower_threshold = -35;
1475 static const int shorter_interval_tie_upper_threshold = -35;
1479 using carrier_uint = uint64_t;
1480 static const int exponent_bits = 11;
1481 static const int kappa = 2;
1482 static const int big_divisor = 1000;
1483 static const int small_divisor = 100;
1484 static const int min_k = -292;
1485 static const int max_k = 341;
1486 static const int shorter_interval_tie_lower_threshold = -77;
1487 static const int shorter_interval_tie_upper_threshold = -77;
1491 template <
typename T>
1492 struct float_info<T, enable_if_t<std::numeric_limits<T>::digits == 64 ||
1493 std::numeric_limits<T>::digits == 113 ||
1495 using carrier_uint = detail::uint128_t;
1496 static const int exponent_bits = 15;
1500 template <
typename T>
1502 using carrier_uint = detail::uint128_t;
1507 significand_type significand;
1511 template <
typename T> FMTQUILL_API
auto to_decimal(T x) noexcept ->
decimal_fp<T>;
1515 template <
typename Float> constexpr
auto has_implicit_bit() ->
bool {
1517 return std::numeric_limits<Float>::digits != 64;
1522 template <
typename Float> constexpr
auto num_significand_bits() ->
int {
1524 return is_float128<Float>() ? 112
1525 : (std::numeric_limits<Float>::digits -
1526 (has_implicit_bit<Float>() ? 1 : 0));
1529 template <
typename Float>
1530 constexpr
auto exponent_mask() ->
1534 << num_significand_bits<Float>();
1536 template <
typename Float> constexpr
auto exponent_bias() ->
int {
1538 return is_float128<Float>() ? 16383
1539 : std::numeric_limits<Float>::max_exponent - 1;
1542 FMTQUILL_CONSTEXPR
inline auto compute_exp_size(
int exp) ->
int {
1543 auto prefix_size = 2;
1544 auto abs_exp = exp >= 0 ? exp : -exp;
1545 if (abs_exp < 100)
return prefix_size + 2;
1546 return prefix_size + (abs_exp >= 1000 ? 4 : 3);
1550 template <
typename Char,
typename OutputIt>
1551 FMTQUILL_CONSTEXPR
auto write_exponent(
int exp, OutputIt out) -> OutputIt {
1552 FMTQUILL_ASSERT(-10000 < exp && exp < 10000,
"exponent out of range");
1554 *out++ =
static_cast<Char
>(
'-');
1557 *out++ =
static_cast<Char
>(
'+');
1559 auto uexp =
static_cast<uint32_t
>(exp);
1560 if (is_constant_evaluated()) {
1561 if (uexp < 10) *out++ =
'0';
1562 return format_decimal<Char>(out, uexp, count_digits(uexp));
1565 const char* top = digits2(uexp / 100);
1566 if (uexp >= 1000u) *out++ =
static_cast<Char
>(top[0]);
1567 *out++ =
static_cast<Char
>(top[1]);
1570 const char* d = digits2(uexp);
1571 *out++ =
static_cast<Char
>(d[0]);
1572 *out++ =
static_cast<Char
>(d[1]);
1581 static constexpr
int num_significand_bits =
1582 static_cast<int>(
sizeof(F) * num_bits<unsigned char>());
1584 constexpr
basic_fp() : f(0), e(0) {}
1585 constexpr basic_fp(uint64_t f_val,
int e_val) : f(f_val), e(e_val) {}
1588 template <
typename Float> FMTQUILL_CONSTEXPR basic_fp(Float n) { assign(n); }
1591 template <typename Float, FMTQUILL_ENABLE_IF(!is_double_double<Float>::value)>
1592 FMTQUILL_CONSTEXPR
auto assign(Float n) ->
bool {
1593 static_assert(std::numeric_limits<Float>::digits <= 113,
"unsupported FP");
1596 const auto num_float_significand_bits =
1597 detail::num_significand_bits<Float>();
1598 const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
1599 const auto significand_mask = implicit_bit - 1;
1600 auto u = bit_cast<carrier_uint>(n);
1601 f =
static_cast<F
>(u & significand_mask);
1602 auto biased_e =
static_cast<int>((u & exponent_mask<Float>()) >>
1603 num_float_significand_bits);
1606 auto is_predecessor_closer = f == 0 && biased_e > 1;
1609 else if (has_implicit_bit<Float>())
1610 f += static_cast<F>(implicit_bit);
1611 e = biased_e - exponent_bias<Float>() - num_float_significand_bits;
1612 if (!has_implicit_bit<Float>()) ++e;
1613 return is_predecessor_closer;
1616 template <typename Float, FMTQUILL_ENABLE_IF(is_double_double<Float>::value)>
1617 FMTQUILL_CONSTEXPR
auto assign(Float n) ->
bool {
1618 static_assert(std::numeric_limits<double>::is_iec559,
"unsupported FP");
1619 return assign(static_cast<double>(n));
1626 template <
int SHIFT = 0,
typename F>
1629 const auto implicit_bit = F(1) << num_significand_bits<double>();
1630 const auto shifted_implicit_bit = implicit_bit << SHIFT;
1631 while ((value.f & shifted_implicit_bit) == 0) {
1637 num_significand_bits<double>() - SHIFT - 1;
1644 FMTQUILL_CONSTEXPR
inline auto multiply(uint64_t lhs, uint64_t rhs) -> uint64_t {
1645 #if FMTQUILL_USE_INT128 1646 auto product =
static_cast<__uint128_t
>(lhs) * rhs;
1647 auto f =
static_cast<uint64_t
>(product >> 64);
1648 return (static_cast<uint64_t>(product) & (1ULL << 63)) != 0 ? f + 1 : f;
1651 uint64_t mask = (1ULL << 32) - 1;
1652 uint64_t a = lhs >> 32, b = lhs & mask;
1653 uint64_t c = rhs >> 32, d = rhs & mask;
1654 uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
1656 uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
1657 return ac + (ad >> 32) + (bc >> 32) + (mid >> 32);
1661 FMTQUILL_CONSTEXPR
inline auto operator*(
fp x,
fp y) ->
fp {
1662 return {multiply(x.f, y.f), x.e + y.e + 64};
1665 template <
typename T,
bool doublish = num_bits<T>() == num_bits<
double>()>
1666 using convert_float_result =
1667 conditional_t<std::is_same<T, float>::value || doublish, double, T>;
1669 template <
typename T>
1670 constexpr
auto convert_float(T value) -> convert_float_result<T> {
1671 return static_cast<convert_float_result<T>
>(value);
1674 template <
bool C,
typename T,
typename F, FMTQUILL_ENABLE_IF(C)>
1675 auto select(T true_value, F) -> T {
1678 template <
bool C,
typename T,
typename F, FMTQUILL_ENABLE_IF(!C)>
1679 auto select(T, F false_value) -> F {
1683 template <
typename Char,
typename OutputIt>
1684 FMTQUILL_CONSTEXPR FMTQUILL_NOINLINE
auto fill(OutputIt it,
size_t n,
1686 auto fill_size = specs.fill_size();
1687 if (fill_size == 1)
return detail::fill_n(it, n, specs.fill_unit<Char>());
1688 if (
const Char* data = specs.fill<Char>()) {
1689 for (
size_t i = 0; i < n; ++i) it = copy<Char>(data, data + fill_size, it);
1697 template <
typename Char, align default_align = align::left,
typename OutputIt,
1699 FMTQUILL_CONSTEXPR
auto write_padded(OutputIt out,
const format_specs& specs,
1700 size_t size,
size_t width, F&& f) -> OutputIt {
1701 static_assert(default_align == align::left || default_align == align::right,
1703 unsigned spec_width = to_unsigned(specs.width);
1704 size_t padding = spec_width > width ? spec_width - width : 0;
1708 default_align == align::left ?
"\x1f\x1f\x00\x01" :
"\x00\x1f\x00\x01";
1709 size_t left_padding = padding >> shifts[
static_cast<int>(specs.align())];
1710 size_t right_padding = padding - left_padding;
1711 auto it = reserve(out, size + padding * specs.fill_size());
1712 if (left_padding != 0) it = fill<Char>(it, left_padding, specs);
1714 if (right_padding != 0) it = fill<Char>(it, right_padding, specs);
1715 return base_iterator(out, it);
1718 template <
typename Char, align default_align = align::left,
typename OutputIt,
1720 constexpr
auto write_padded(OutputIt out,
const format_specs& specs,
1721 size_t size, F&& f) -> OutputIt {
1722 return write_padded<Char, default_align>(out, specs, size, size, f);
1725 template <
typename Char, align default_align = align::left,
typename OutputIt>
1728 return write_padded<Char, default_align>(
1729 out, specs, bytes.
size(), [bytes](reserve_iterator<OutputIt> it) {
1730 const char* data = bytes.
data();
1731 return copy<Char>(data, data + bytes.
size(), it);
1735 template <
typename Char,
typename OutputIt,
typename UIntPtr>
1736 auto write_ptr(OutputIt out, UIntPtr value,
const format_specs* specs)
1738 int num_digits = count_digits<4>(value);
1739 auto size = to_unsigned(num_digits) + size_t(2);
1740 auto write = [=](reserve_iterator<OutputIt> it) {
1741 *it++ =
static_cast<Char
>(
'0');
1742 *it++ =
static_cast<Char
>(
'x');
1743 return format_base2e<Char>(4, it, value, num_digits);
1745 return specs ? write_padded<Char, align::right>(out, *specs, size, write)
1746 : base_iterator(out, write(reserve(out, size)));
1750 FMTQUILL_API
auto is_printable(uint32_t cp) -> bool;
1752 inline auto needs_escape(uint32_t cp) ->
bool {
1753 if (cp < 0x20 || cp == 0x7f || cp ==
'"' || cp ==
'\\')
return true;
1754 if (const_check(FMTQUILL_OPTIMIZE_SIZE > 1))
return false;
1755 return !is_printable(cp);
1764 template <
typename Char>
1765 auto find_escape(
const Char* begin,
const Char* end)
1767 for (; begin != end; ++begin) {
1768 uint32_t cp =
static_cast<unsigned_char<Char>
>(*begin);
1769 if (const_check(
sizeof(Char) == 1) && cp >= 0x80)
continue;
1770 if (needs_escape(cp))
return {begin, begin + 1, cp};
1772 return {begin,
nullptr, 0};
1775 inline auto find_escape(
const char* begin,
const char* end)
1777 if (const_check(!use_utf8))
return find_escape<char>(begin, end);
1779 for_each_codepoint(
string_view(begin, to_unsigned(end - begin)),
1781 if (needs_escape(cp)) {
1782 result = {sv.begin(), sv.end(), cp};
1790 template <
size_t w
idth,
typename Char,
typename OutputIt>
1791 auto write_codepoint(OutputIt out,
char prefix, uint32_t cp) -> OutputIt {
1792 *out++ =
static_cast<Char
>(
'\\');
1793 *out++ =
static_cast<Char
>(prefix);
1795 fill_n(buf, width, static_cast<Char>(
'0'));
1796 format_base2e(4, buf, cp, width);
1797 return copy<Char>(buf, buf + width, out);
1800 template <
typename OutputIt,
typename Char>
1803 auto c =
static_cast<Char
>(escape.cp);
1804 switch (escape.cp) {
1806 *out++ =
static_cast<Char
>(
'\\');
1807 c =
static_cast<Char
>(
'n');
1810 *out++ =
static_cast<Char
>(
'\\');
1811 c =
static_cast<Char
>(
'r');
1814 *out++ =
static_cast<Char
>(
'\\');
1815 c =
static_cast<Char
>(
't');
1817 case '"': FMTQUILL_FALLTHROUGH;
1818 case '\'': FMTQUILL_FALLTHROUGH;
1819 case '\\': *out++ =
static_cast<Char
>(
'\\');
break;
1821 if (escape.cp < 0x100)
return write_codepoint<2, Char>(out,
'x', escape.cp);
1822 if (escape.cp < 0x10000)
1823 return write_codepoint<4, Char>(out,
'u', escape.cp);
1824 if (escape.cp < 0x110000)
1825 return write_codepoint<8, Char>(out,
'U', escape.cp);
1827 escape.begin, to_unsigned(escape.end - escape.begin))) {
1828 out = write_codepoint<2, Char>(out,
'x',
1829 static_cast<uint32_t
>(escape_char) & 0xFF);
1837 template <
typename Char,
typename OutputIt>
1840 *out++ =
static_cast<Char
>(
'"');
1841 auto begin = str.begin(), end = str.end();
1843 auto escape = find_escape(begin, end);
1844 out = copy<Char>(begin, escape.begin, out);
1847 out = write_escaped_cp<OutputIt, Char>(out, escape);
1848 }
while (begin != end);
1849 *out++ =
static_cast<Char
>(
'"');
1853 template <
typename Char,
typename OutputIt>
1854 auto write_escaped_char(OutputIt out, Char v) -> OutputIt {
1855 Char v_array[1] = {v};
1856 *out++ =
static_cast<Char
>(
'\'');
1857 if ((needs_escape(static_cast<uint32_t>(v)) && v != static_cast<Char>(
'"')) ||
1858 v ==
static_cast<Char
>(
'\'')) {
1859 out = write_escaped_cp(out,
1861 static_cast<uint32_t
>(v)});
1865 *out++ =
static_cast<Char
>(
'\'');
1869 template <
typename Char,
typename OutputIt>
1870 FMTQUILL_CONSTEXPR
auto write_char(OutputIt out, Char value,
1872 bool is_debug = specs.type() == presentation_type::debug;
1873 return write_padded<Char>(out, specs, 1, [=](reserve_iterator<OutputIt> it) {
1874 if (is_debug)
return write_escaped_char(it, value);
1882 std::string grouping_;
1883 std::basic_string<Char> thousands_sep_;
1886 std::string::const_iterator group;
1889 auto initial_state()
const -> next_state {
return {grouping_.begin(), 0}; }
1892 auto next(next_state& state)
const ->
int {
1893 if (thousands_sep_.empty())
return max_value<int>();
1894 if (state.group == grouping_.end())
return state.pos += grouping_.back();
1895 if (*state.group <= 0 || *state.group == max_value<char>())
1896 return max_value<int>();
1897 state.pos += *state.group++;
1903 if (!localized)
return;
1904 auto sep = thousands_sep<Char>(loc);
1905 grouping_ = sep.grouping;
1906 if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep);
1908 digit_grouping(std::string grouping, std::basic_string<Char> sep)
1909 : grouping_(std::move(grouping)), thousands_sep_(std::move(sep)) {}
1911 auto has_separator()
const ->
bool {
return !thousands_sep_.empty(); }
1913 auto count_separators(
int num_digits)
const ->
int {
1915 auto state = initial_state();
1916 while (num_digits > next(state)) ++count;
1921 template <
typename Out,
typename C>
1923 auto num_digits =
static_cast<int>(digits.
size());
1925 separators.push_back(0);
1926 auto state = initial_state();
1927 while (
int i = next(state)) {
1928 if (i >= num_digits)
break;
1929 separators.push_back(i);
1931 for (
int i = 0, sep_index = static_cast<int>(separators.size() - 1);
1932 i < num_digits; ++i) {
1933 if (num_digits - i == separators[sep_index]) {
1934 out = copy<Char>(thousands_sep_.data(),
1935 thousands_sep_.data() + thousands_sep_.size(), out);
1938 *out++ =
static_cast<Char
>(digits[to_unsigned(i)]);
1944 FMTQUILL_CONSTEXPR
inline void prefix_append(
unsigned& prefix,
unsigned value) {
1945 prefix |= prefix != 0 ? value << 8 : value;
1946 prefix += (1u + (value > 0xff ? 1 : 0)) << 24;
1950 template <
typename OutputIt,
typename UInt,
typename Char>
1951 auto write_int(OutputIt out, UInt value,
unsigned prefix,
1954 static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value,
"");
1957 switch (specs.type()) {
1958 default: FMTQUILL_ASSERT(
false,
""); FMTQUILL_FALLTHROUGH;
1959 case presentation_type::none:
1960 case presentation_type::dec:
1961 num_digits = count_digits(value);
1964 case presentation_type::hex:
1966 prefix_append(prefix,
unsigned(specs.upper() ?
'X' :
'x') << 8 |
'0');
1967 num_digits = count_digits<4>(value);
1968 format_base2e<char>(4,
appender(
buffer), value, num_digits, specs.upper());
1970 case presentation_type::oct:
1971 num_digits = count_digits<3>(value);
1974 if (specs.alt() && specs.precision <= num_digits && value != 0)
1975 prefix_append(prefix,
'0');
1978 case presentation_type::bin:
1980 prefix_append(prefix,
unsigned(specs.upper() ?
'B' :
'b') << 8 |
'0');
1981 num_digits = count_digits<1>(value);
1984 case presentation_type::chr:
1985 return write_char<Char>(out,
static_cast<Char
>(value), specs);
1988 unsigned size = (prefix != 0 ? prefix >> 24 : 0) + to_unsigned(num_digits) +
1989 to_unsigned(grouping.count_separators(num_digits));
1990 return write_padded<Char, align::right>(
1991 out, specs, size, size, [&](reserve_iterator<OutputIt> it) {
1992 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
1993 *it++ = static_cast<Char>(p & 0xff);
1998 #if FMTQUILL_USE_LOCALE 2005 template <
typename OutputIt>
2016 template <
typename T>
2017 FMTQUILL_CONSTEXPR
auto make_write_int_arg(T value, sign s)
2020 auto abs_value =
static_cast<uint32_or_64_or_128_t<T>
>(value);
2021 if (is_negative(value)) {
2022 prefix = 0x01000000 |
'-';
2023 abs_value = 0 - abs_value;
2025 constexpr
unsigned prefixes[4] = {0, 0, 0x1000000u |
'+', 0x1000000u |
' '};
2026 prefix = prefixes[
static_cast<int>(s)];
2028 return {abs_value, prefix};
2034 std::basic_string<Char> sep;
2035 std::string grouping;
2036 std::basic_string<Char> decimal_point;
2038 template <typename T, FMTQUILL_ENABLE_IF(is_integer<T>::value)>
2039 auto operator()(T value) ->
bool {
2040 auto arg = make_write_int_arg(value, specs.sign());
2041 write_int(out,
static_cast<uint64_or_128_t<T>
>(arg.abs_value), arg.prefix,
2046 template <typename T, FMTQUILL_ENABLE_IF(!is_integer<T>::value)>
2047 auto operator()(T) ->
bool {
2057 FMTQUILL_CONSTEXPR
size_padding(
int num_digits,
unsigned prefix,
2059 : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) {
2060 if (specs.align() == align::numeric) {
2061 auto width = to_unsigned(specs.width);
2063 padding = width - size;
2066 }
else if (specs.precision > num_digits) {
2067 size = (prefix >> 24) + to_unsigned(specs.precision);
2068 padding = to_unsigned(specs.precision - num_digits);
2073 template <
typename Char,
typename OutputIt,
typename T>
2074 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
auto write_int(OutputIt out,
write_int_arg<T> arg,
2076 static_assert(std::is_same<T, uint32_or_64_or_128_t<T>>::value,
"");
2078 constexpr
size_t buffer_size = num_bits<T>();
2079 char buffer[buffer_size];
2080 if (is_constant_evaluated()) fill_n(buffer, buffer_size,
'\0');
2081 const char* begin =
nullptr;
2082 const char* end = buffer + buffer_size;
2084 auto abs_value = arg.abs_value;
2085 auto prefix = arg.prefix;
2086 switch (specs.type()) {
2087 default: FMTQUILL_ASSERT(
false,
""); FMTQUILL_FALLTHROUGH;
2088 case presentation_type::none:
2089 case presentation_type::dec:
2090 begin = do_format_decimal(buffer, abs_value, buffer_size);
2092 case presentation_type::hex:
2093 begin = do_format_base2e(4, buffer, abs_value, buffer_size, specs.upper());
2095 prefix_append(prefix,
unsigned(specs.upper() ?
'X' :
'x') << 8 |
'0');
2097 case presentation_type::oct: {
2098 begin = do_format_base2e(3, buffer, abs_value, buffer_size);
2101 auto num_digits = end - begin;
2102 if (specs.alt() && specs.precision <= num_digits && abs_value != 0)
2103 prefix_append(prefix,
'0');
2106 case presentation_type::bin:
2107 begin = do_format_base2e(1, buffer, abs_value, buffer_size);
2109 prefix_append(prefix,
unsigned(specs.upper() ?
'B' :
'b') << 8 |
'0');
2111 case presentation_type::chr:
2112 return write_char<Char>(out,
static_cast<Char
>(abs_value), specs);
2118 int num_digits =
static_cast<int>(end - begin);
2120 if ((specs.width | (specs.precision + 1)) == 0) {
2121 auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24));
2122 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
2123 *it++ = static_cast<Char>(p & 0xff);
2124 return base_iterator(out, copy<Char>(begin, end, it));
2127 unsigned padding = sp.padding;
2128 return write_padded<Char, align::right>(
2129 out, specs, sp.size, [=](reserve_iterator<OutputIt> it) {
2130 for (
unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
2131 *it++ = static_cast<Char>(p & 0xff);
2132 it = detail::fill_n(it, padding, static_cast<Char>(
'0'));
2133 return copy<Char>(begin, end, it);
2137 template <
typename Char,
typename OutputIt,
typename T>
2138 FMTQUILL_CONSTEXPR FMTQUILL_NOINLINE
auto write_int_noinline(OutputIt out,
2142 return write_int<Char>(out, arg, specs);
2145 template <
typename Char,
typename T,
2147 !std::is_same<T, bool>::value &&
2148 !std::is_same<T, Char>::value)>
2152 if (specs.localized() && write_loc(out, value, specs, loc))
return out;
2153 return write_int_noinline<Char>(out, make_write_int_arg(value, specs.sign()),
2158 template <
typename Char,
typename OutputIt,
typename T,
2160 !std::is_same<T, bool>::value &&
2161 !std::is_same<T, Char>::value &&
2163 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
auto write(OutputIt out, T value,
2166 if (specs.localized() && write_loc(out, value, specs, loc))
return out;
2167 return write_int<Char>(out, make_write_int_arg(value, specs.sign()), specs);
2170 template <
typename Char,
typename OutputIt>
2171 FMTQUILL_CONSTEXPR
auto write(OutputIt out, Char value,
const format_specs& specs,
2174 using unsigned_type =
2175 conditional_t<std::is_same<Char, char>::value,
unsigned char,
unsigned>;
2176 return check_char_specs(specs)
2177 ? write_char<Char>(out, value, specs)
2178 : write<Char>(out, static_cast<unsigned_type>(value), specs, loc);
2181 template <
typename Char,
typename OutputIt,
2182 FMTQUILL_ENABLE_IF(std::is_same<Char, char>::value)>
2185 bool is_debug = specs.type() == presentation_type::debug;
2186 if (specs.precision < 0 && specs.width == 0) {
2187 auto&& it = reserve(out, s.
size());
2188 return is_debug ? write_escaped_string(it, s) : copy<char>(s, it);
2191 size_t display_width_limit =
2192 specs.precision < 0 ? SIZE_MAX : to_unsigned(specs.precision);
2193 size_t display_width =
2194 !is_debug || specs.precision == 0 ? 0 : 1;
2195 size_t size = !is_debug || specs.precision == 0 ? 0 : 1;
2196 for_each_codepoint(s, [&](uint32_t cp,
string_view sv) {
2197 if (is_debug && needs_escape(cp)) {
2203 size_t cp_width = buf.count();
2204 if (display_width + cp_width <= display_width_limit) {
2205 display_width += cp_width;
2208 if (display_width < display_width_limit && sv.end() == s.end()) {
2215 size += display_width_limit - display_width;
2216 display_width = display_width_limit;
2220 size_t cp_width = display_width_of(cp);
2221 if (cp_width + display_width <= display_width_limit) {
2222 display_width += cp_width;
2225 if (is_debug && display_width < display_width_limit &&
2226 sv.end() == s.end()) {
2236 struct bounded_output_iterator {
2237 reserve_iterator<OutputIt> underlying_iterator;
2240 FMTQUILL_CONSTEXPR
auto operator*() -> bounded_output_iterator& {
return *
this; }
2241 FMTQUILL_CONSTEXPR
auto operator++() -> bounded_output_iterator& {
2244 FMTQUILL_CONSTEXPR
auto operator++(
int) -> bounded_output_iterator& {
2247 FMTQUILL_CONSTEXPR
auto operator=(
char c) -> bounded_output_iterator& {
2249 *underlying_iterator++ = c;
2256 return write_padded<char>(
2257 out, specs, size, display_width, [=](reserve_iterator<OutputIt> it) {
2259 ? write_escaped_string(bounded_output_iterator{it, size}, s)
2260 .underlying_iterator
2261 : copy<char>(s.
data(), s.
data() + size, it);
2265 template <
typename Char,
typename OutputIt,
2266 FMTQUILL_ENABLE_IF(!std::is_same<Char, char>::value)>
2269 auto data = s.
data();
2270 auto size = s.
size();
2271 if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
2272 size = to_unsigned(specs.precision);
2274 bool is_debug = specs.type() == presentation_type::debug;
2281 return write_padded<Char>(
2282 out, specs, size, [=](reserve_iterator<OutputIt> it) {
2283 return is_debug ? write_escaped_string(it, s)
2284 : copy<Char>(data, data + size, it);
2288 template <
typename Char,
typename OutputIt>
2291 return write<Char>(out, s, specs);
2294 template <
typename Char,
typename OutputIt>
2295 FMTQUILL_CONSTEXPR
auto write(OutputIt out,
const Char* s,
const format_specs& specs,
2297 if (specs.type() == presentation_type::pointer)
2298 return write_ptr<Char>(out, bit_cast<uintptr_t>(s), &specs);
2299 if (!s) report_error(
"string pointer is null");
2303 template <
typename Char,
typename OutputIt,
typename T,
2305 !std::is_same<T, bool>::value &&
2306 !std::is_same<T, Char>::value)>
2307 FMTQUILL_CONSTEXPR
auto write(OutputIt out, T value) -> OutputIt {
2308 auto abs_value =
static_cast<uint32_or_64_or_128_t<T>
>(value);
2309 bool negative = is_negative(value);
2311 if (negative) abs_value = ~abs_value + 1;
2312 int num_digits = count_digits(abs_value);
2313 auto size = (negative ? 1 : 0) + static_cast<size_t>(num_digits);
2314 if (
auto ptr = to_pointer<Char>(out, size)) {
2315 if (negative) *ptr++ =
static_cast<Char
>(
'-');
2316 format_decimal<Char>(ptr, abs_value, num_digits);
2319 if (negative) *out++ =
static_cast<Char
>(
'-');
2320 return format_decimal<Char>(out, abs_value, num_digits);
2323 template <
typename Char>
2324 FMTQUILL_CONSTEXPR
auto parse_align(
const Char* begin,
const Char* end,
2326 FMTQUILL_ASSERT(begin != end,
"");
2327 auto alignment = align::none;
2328 auto p = begin + code_point_length(begin);
2329 if (end - p <= 0) p = begin;
2331 switch (to_ascii(*p)) {
2332 case '<': alignment = align::left;
break;
2333 case '>': alignment = align::right;
break;
2334 case '^': alignment = align::center;
break;
2336 if (alignment != align::none) {
2339 if (c ==
'}')
return begin;
2341 report_error(
"invalid fill character '{'");
2350 }
else if (p == begin) {
2355 specs.set_align(alignment);
2359 template <
typename Char,
typename OutputIt>
2360 FMTQUILL_CONSTEXPR20
auto write_nonfinite(OutputIt out,
bool isnan,
2363 isnan ? (specs.upper() ?
"NAN" :
"nan") : (specs.upper() ?
"INF" :
"inf");
2364 constexpr
size_t str_size = 3;
2365 auto size = str_size + (s != sign::none ? 1 : 0);
2367 const bool is_zero_fill =
2368 specs.fill_size() == 1 && specs.fill_unit<Char>() ==
'0';
2369 if (is_zero_fill) specs.set_fill(
' ');
2370 return write_padded<Char>(out, specs, size,
2371 [=](reserve_iterator<OutputIt> it) {
2372 if (s != sign::none)
2373 *it++ = detail::getsign<Char>(s);
2374 return copy<Char>(str, str + str_size, it);
2380 const char* significand;
2381 int significand_size;
2385 constexpr
auto get_significand_size(
const big_decimal_fp& f) ->
int {
2386 return f.significand_size;
2388 template <
typename T>
2390 return count_digits(f.significand);
2393 template <
typename Char,
typename OutputIt>
2394 constexpr
auto write_significand(OutputIt out,
const char* significand,
2395 int significand_size) -> OutputIt {
2396 return copy<Char>(significand, significand + significand_size, out);
2398 template <
typename Char,
typename OutputIt,
typename UInt>
2399 inline auto write_significand(OutputIt out, UInt significand,
2400 int significand_size) -> OutputIt {
2401 return format_decimal<Char>(out, significand, significand_size);
2403 template <
typename Char,
typename OutputIt,
typename T,
typename Grouping>
2404 FMTQUILL_CONSTEXPR20
auto write_significand(OutputIt out, T significand,
2405 int significand_size,
int exponent,
2406 const Grouping& grouping) -> OutputIt {
2407 if (!grouping.has_separator()) {
2408 out = write_significand<Char>(out, significand, significand_size);
2409 return detail::fill_n(out, exponent, static_cast<Char>(
'0'));
2412 write_significand<char>(
appender(
buffer), significand, significand_size);
2417 template <
typename Char,
typename UInt,
2418 FMTQUILL_ENABLE_IF(std::is_integral<UInt>::value)>
2419 inline auto write_significand(Char* out, UInt significand,
int significand_size,
2420 int integral_size, Char decimal_point) -> Char* {
2421 if (!decimal_point)
return format_decimal(out, significand, significand_size);
2422 out += significand_size + 1;
2424 int floating_size = significand_size - integral_size;
2425 for (
int i = floating_size / 2; i > 0; --i) {
2427 write2digits(out, static_cast<size_t>(significand % 100));
2430 if (floating_size % 2 != 0) {
2431 *--out =
static_cast<Char
>(
'0' + significand % 10);
2434 *--out = decimal_point;
2435 format_decimal(out - integral_size, significand, integral_size);
2439 template <
typename OutputIt,
typename UInt,
typename Char,
2440 FMTQUILL_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)>
2441 inline auto write_significand(OutputIt out, UInt significand,
2442 int significand_size,
int integral_size,
2443 Char decimal_point) -> OutputIt {
2445 Char
buffer[digits10<UInt>() + 2];
2446 auto end = write_significand(
buffer, significand, significand_size,
2447 integral_size, decimal_point);
2448 return detail::copy_noinline<Char>(
buffer, end, out);
2451 template <
typename OutputIt,
typename Char>
2452 FMTQUILL_CONSTEXPR
auto write_significand(OutputIt out,
const char* significand,
2453 int significand_size,
int integral_size,
2454 Char decimal_point) -> OutputIt {
2455 out = detail::copy_noinline<Char>(significand, significand + integral_size,
2457 if (!decimal_point)
return out;
2458 *out++ = decimal_point;
2459 return detail::copy_noinline<Char>(significand + integral_size,
2460 significand + significand_size, out);
2463 template <
typename OutputIt,
typename Char,
typename T,
typename Grouping>
2464 FMTQUILL_CONSTEXPR20
auto write_significand(OutputIt out, T significand,
2465 int significand_size,
int integral_size,
2467 const Grouping& grouping) -> OutputIt {
2468 if (!grouping.has_separator()) {
2469 return write_significand(out, significand, significand_size, integral_size,
2474 integral_size, decimal_point);
2477 return detail::copy_noinline<Char>(
buffer.
data() + integral_size,
2483 template <
typename T> FMTQUILL_CONSTEVAL
auto exp_upper() ->
int {
2484 return std::numeric_limits<T>::digits10 != 0
2485 ? min_of(16, std::numeric_limits<T>::digits10 + 1)
2491 constexpr
auto use_fixed(
int exp,
int exp_upper) ->
bool {
2492 return exp >= -4 && exp < exp_upper;
2499 constexpr
auto has_separator()
const ->
bool {
return false; }
2501 constexpr
auto count_separators(
int)
const ->
int {
return 0; }
2503 template <
typename Out,
typename C>
2509 template <
typename Char,
typename Grouping,
typename OutputIt,
2511 FMTQUILL_CONSTEXPR20
auto write_fixed(OutputIt out,
const DecimalFP& f,
2512 int significand_size, Char decimal_point,
2515 using iterator = reserve_iterator<OutputIt>;
2517 int exp = f.exponent + significand_size;
2518 long long size = significand_size + (s != sign::none ? 1 : 0);
2519 if (f.exponent >= 0) {
2522 int num_zeros = specs.precision - exp;
2523 abort_fuzzing_if(num_zeros > 5000);
2526 if (num_zeros <= 0 && specs.type() != presentation_type::fixed)
2528 if (num_zeros > 0) size += num_zeros;
2530 auto grouping = Grouping(loc, specs.localized());
2531 size += grouping.count_separators(exp);
2532 return write_padded<Char, align::right>(
2533 out, specs,
static_cast<size_t>(size), [&](iterator it) {
2534 if (s != sign::none) *it++ = detail::getsign<Char>(s);
2535 it = write_significand<Char>(it, f.significand, significand_size,
2536 f.exponent, grouping);
2537 if (!specs.alt())
return it;
2538 *it++ = decimal_point;
2539 return num_zeros > 0 ? detail::fill_n(it, num_zeros, Char(
'0')) : it;
2544 int num_zeros = specs.alt() ? specs.precision - significand_size : 0;
2545 size += 1 + max_of(num_zeros, 0);
2546 auto grouping = Grouping(loc, specs.localized());
2547 size += grouping.count_separators(exp);
2548 return write_padded<Char, align::right>(
2549 out, specs, to_unsigned(size), [&](iterator it) {
2550 if (s != sign::none) *it++ = detail::getsign<Char>(s);
2551 it = write_significand(it, f.significand, significand_size, exp,
2552 decimal_point, grouping);
2553 return num_zeros > 0 ? detail::fill_n(it, num_zeros, Char(
'0')) : it;
2557 int num_zeros = -exp;
2558 if (significand_size == 0 && specs.precision >= 0 &&
2559 specs.precision < num_zeros) {
2560 num_zeros = specs.precision;
2562 bool pointy = num_zeros != 0 || significand_size != 0 || specs.alt();
2563 size += 1 + (pointy ? 1 : 0) + num_zeros;
2564 return write_padded<Char, align::right>(
2565 out, specs, to_unsigned(size), [&](iterator it) {
2566 if (s != sign::none) *it++ = detail::getsign<Char>(s);
2568 if (!pointy)
return it;
2569 *it++ = decimal_point;
2570 it = detail::fill_n(it, num_zeros, Char(
'0'));
2571 return write_significand<Char>(it, f.significand, significand_size);
2575 template <
typename Char,
typename Grouping,
typename OutputIt,
2577 FMTQUILL_CONSTEXPR20
auto do_write_float(OutputIt out,
const DecimalFP& f,
2580 Char point = specs.localized() ? detail::decimal_point<Char>(loc) : Char(
'.');
2581 int significand_size = get_significand_size(f);
2582 int exp = f.exponent + significand_size - 1;
2583 if (specs.type() == presentation_type::fixed ||
2584 (specs.type() != presentation_type::exp &&
2585 use_fixed(exp, specs.precision > 0 ? specs.precision : exp_upper))) {
2586 return write_fixed<Char, Grouping>(out, f, significand_size, point, specs,
2592 long long size = significand_size + (s != sign::none ? 1 : 0);
2594 num_zeros = max_of(specs.precision - significand_size, 0);
2596 }
else if (significand_size == 1) {
2599 size += (point ? 1 : 0) + compute_exp_size(exp);
2600 char exp_char = specs.upper() ?
'E' :
'e';
2601 auto write = [=](reserve_iterator<OutputIt> it) {
2602 if (s != sign::none) *it++ = detail::getsign<Char>(s);
2604 it = write_significand(it, f.significand, significand_size, 1, point);
2605 if (num_zeros > 0) it = detail::fill_n(it, num_zeros, Char(
'0'));
2606 *it++ = Char(exp_char);
2607 return write_exponent<Char>(exp, it);
2609 auto usize = to_unsigned(size);
2610 return specs.width > 0
2611 ? write_padded<Char, align::right>(out, specs, usize, write)
2612 : base_iterator(out, write(reserve(out, usize)));
2615 template <
typename Char,
typename OutputIt,
typename DecimalFP>
2616 FMTQUILL_CONSTEXPR20
auto write_float(OutputIt out,
const DecimalFP& f,
2619 if (is_constant_evaluated()) {
2620 return do_write_float<Char, fallback_digit_grouping<Char>>(out, f, specs, s,
2623 return do_write_float<Char, digit_grouping<Char>>(out, f, specs, s,
2628 template <
typename T> constexpr
auto isnan(T value) ->
bool {
2629 return value != value;
2632 template <
typename T,
typename Enable =
void>
2635 template <
typename T>
2637 : std::true_type {};
2639 template <
typename T,
2641 FMTQUILL_CONSTEXPR20
auto isfinite(T value) ->
bool {
2642 constexpr T inf = T(std::numeric_limits<double>::infinity());
2643 if (is_constant_evaluated())
2645 return std::isfinite(value);
2647 template <typename T, FMTQUILL_ENABLE_IF(!has_isfinite<T>::value)>
2648 FMTQUILL_CONSTEXPR
auto isfinite(T value) ->
bool {
2649 T inf = T(std::numeric_limits<double>::infinity());
2654 template <typename T, FMTQUILL_ENABLE_IF(is_floating_point<T>::value)>
2655 FMTQUILL_INLINE FMTQUILL_CONSTEXPR
auto signbit(T value) ->
bool {
2656 if (is_constant_evaluated()) {
2657 #ifdef __cpp_if_constexpr 2658 if constexpr (std::numeric_limits<double>::is_iec559) {
2659 auto bits = detail::bit_cast<uint64_t>(
static_cast<double>(value));
2660 return (bits >> (num_bits<uint64_t>() - 1)) != 0;
2664 return std::signbit(static_cast<double>(value));
2667 inline FMTQUILL_CONSTEXPR20
void adjust_precision(
int& precision,
int exp10) {
2670 if (exp10 > 0 && precision > max_value<int>() - exp10)
2671 FMTQUILL_THROW(format_error(
"number is too big"));
2678 using bigit = uint32_t;
2679 using double_bigit = uint64_t;
2680 enum { bigit_bits = num_bits<bigit>() };
2681 enum { bigits_capacity = 32 };
2687 FMTQUILL_CONSTEXPR
auto get_bigit(
int i)
const -> bigit {
2688 return i >= exp_ && i < num_bigits() ? bigits_[i - exp_] : 0;
2691 FMTQUILL_CONSTEXPR
void subtract_bigits(
int index, bigit other, bigit& borrow) {
2692 auto result = double_bigit(bigits_[index]) - other - borrow;
2693 bigits_[index] =
static_cast<bigit
>(result);
2694 borrow =
static_cast<bigit
>(result >> (bigit_bits * 2 - 1));
2697 FMTQUILL_CONSTEXPR
void remove_leading_zeros() {
2698 int num_bigits =
static_cast<int>(bigits_.
size()) - 1;
2699 while (num_bigits > 0 && bigits_[num_bigits] == 0) --num_bigits;
2700 bigits_.
resize(to_unsigned(num_bigits + 1));
2704 FMTQUILL_CONSTEXPR
void subtract_aligned(
const bigint& other) {
2705 FMTQUILL_ASSERT(other.exp_ >= exp_,
"unaligned bigints");
2706 FMTQUILL_ASSERT(compare(*
this, other) >= 0,
"");
2708 int i = other.exp_ - exp_;
2709 for (
size_t j = 0, n = other.bigits_.
size(); j != n; ++i, ++j)
2710 subtract_bigits(i, other.bigits_[j], borrow);
2711 if (borrow != 0) subtract_bigits(i, 0, borrow);
2712 FMTQUILL_ASSERT(borrow == 0,
"");
2713 remove_leading_zeros();
2716 FMTQUILL_CONSTEXPR
void multiply(uint32_t value) {
2718 const double_bigit wide_value = value;
2719 for (
size_t i = 0, n = bigits_.
size(); i < n; ++i) {
2720 double_bigit result = bigits_[i] * wide_value + carry;
2721 bigits_[i] =
static_cast<bigit
>(result);
2722 carry =
static_cast<bigit
>(result >> bigit_bits);
2724 if (carry != 0) bigits_.push_back(carry);
2727 template <typename UInt, FMTQUILL_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
2728 std::is_same<UInt, uint128_t>::value)>
2729 FMTQUILL_CONSTEXPR
void multiply(UInt value) {
2731 conditional_t<std::is_same<UInt, uint128_t>::value, uint64_t, uint32_t>;
2732 const int shift = num_bits<half_uint>() - bigit_bits;
2733 const UInt lower =
static_cast<half_uint
>(value);
2734 const UInt upper = value >> num_bits<half_uint>();
2736 for (
size_t i = 0, n = bigits_.
size(); i < n; ++i) {
2737 UInt result = lower * bigits_[i] +
static_cast<bigit
>(carry);
2738 carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) +
2739 (carry >> bigit_bits);
2740 bigits_[i] =
static_cast<bigit
>(result);
2742 while (carry != 0) {
2743 bigits_.push_back(static_cast<bigit>(carry));
2744 carry >>= bigit_bits;
2748 template <typename UInt, FMTQUILL_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
2749 std::is_same<UInt, uint128_t>::value)>
2750 FMTQUILL_CONSTEXPR
void assign(UInt n) {
2751 size_t num_bigits = 0;
2753 bigits_[num_bigits++] =
static_cast<bigit
>(n);
2756 bigits_.
resize(num_bigits);
2761 FMTQUILL_CONSTEXPR bigint() : exp_(0) {}
2762 explicit bigint(uint64_t n) { assign(n); }
2764 bigint(
const bigint&) =
delete;
2765 void operator=(
const bigint&) =
delete;
2767 FMTQUILL_CONSTEXPR
void assign(
const bigint& other) {
2768 auto size = other.bigits_.
size();
2770 auto data = other.bigits_.
data();
2771 copy<bigit>(data, data + size, bigits_.
data());
2775 template <
typename Int> FMTQUILL_CONSTEXPR
void operator=(Int n) {
2776 FMTQUILL_ASSERT(n > 0,
"");
2777 assign(uint64_or_128_t<Int>(n));
2780 FMTQUILL_CONSTEXPR
auto num_bigits()
const ->
int {
2781 return static_cast<int>(bigits_.
size()) + exp_;
2784 FMTQUILL_CONSTEXPR
auto operator<<=(
int shift) -> bigint& {
2785 FMTQUILL_ASSERT(shift >= 0,
"");
2786 exp_ += shift / bigit_bits;
2787 shift %= bigit_bits;
2788 if (shift == 0)
return *
this;
2790 for (
size_t i = 0, n = bigits_.
size(); i < n; ++i) {
2791 bigit c = bigits_[i] >> (bigit_bits - shift);
2792 bigits_[i] = (bigits_[i] << shift) + carry;
2795 if (carry != 0) bigits_.push_back(carry);
2799 template <
typename Int> FMTQUILL_CONSTEXPR
auto operator*=(Int value) -> bigint& {
2800 FMTQUILL_ASSERT(value > 0,
"");
2801 multiply(uint32_or_64_or_128_t<Int>(value));
2805 friend FMTQUILL_CONSTEXPR
auto compare(
const bigint& b1,
const bigint& b2) ->
int {
2806 int num_bigits1 = b1.num_bigits(), num_bigits2 = b2.num_bigits();
2807 if (num_bigits1 != num_bigits2)
return num_bigits1 > num_bigits2 ? 1 : -1;
2808 int i =
static_cast<int>(b1.bigits_.
size()) - 1;
2809 int j =
static_cast<int>(b2.bigits_.
size()) - 1;
2811 if (end < 0) end = 0;
2812 for (; i >= end; --i, --j) {
2813 bigit b1_bigit = b1.bigits_[i], b2_bigit = b2.bigits_[j];
2814 if (b1_bigit != b2_bigit)
return b1_bigit > b2_bigit ? 1 : -1;
2816 if (i != j)
return i > j ? 1 : -1;
2821 friend FMTQUILL_CONSTEXPR
auto add_compare(
const bigint& lhs1,
const bigint& lhs2,
2822 const bigint& rhs) ->
int {
2823 int max_lhs_bigits = max_of(lhs1.num_bigits(), lhs2.num_bigits());
2824 int num_rhs_bigits = rhs.num_bigits();
2825 if (max_lhs_bigits + 1 < num_rhs_bigits)
return -1;
2826 if (max_lhs_bigits > num_rhs_bigits)
return 1;
2827 double_bigit borrow = 0;
2828 int min_exp = min_of(min_of(lhs1.exp_, lhs2.exp_), rhs.exp_);
2829 for (
int i = num_rhs_bigits - 1; i >= min_exp; --i) {
2830 double_bigit sum = double_bigit(lhs1.get_bigit(i)) + lhs2.get_bigit(i);
2831 bigit rhs_bigit = rhs.get_bigit(i);
2832 if (sum > rhs_bigit + borrow)
return 1;
2833 borrow = rhs_bigit + borrow - sum;
2834 if (borrow > 1)
return -1;
2835 borrow <<= bigit_bits;
2837 return borrow != 0 ? -1 : 0;
2841 FMTQUILL_CONSTEXPR20
void assign_pow10(
int exp) {
2842 FMTQUILL_ASSERT(exp >= 0,
"");
2843 if (exp == 0)
return *
this = 1;
2844 int bitmask = 1 << (num_bits<unsigned>() -
2845 countl_zero(static_cast<uint32_t>(exp)) - 1);
2850 while (bitmask != 0) {
2852 if ((exp & bitmask) != 0) *
this *= 5;
2858 FMTQUILL_CONSTEXPR20
void square() {
2859 int num_bigits =
static_cast<int>(bigits_.
size());
2860 int num_result_bigits = 2 * num_bigits;
2862 bigits_.
resize(to_unsigned(num_result_bigits));
2863 auto sum = uint128_t();
2864 for (
int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) {
2867 for (
int i = 0, j = bigit_index; j >= 0; ++i, --j) {
2869 sum += double_bigit(n[i]) * n[j];
2871 bigits_[bigit_index] =
static_cast<bigit
>(sum);
2872 sum >>= num_bits<bigit>();
2875 for (
int bigit_index = num_bigits; bigit_index < num_result_bigits;
2877 for (
int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;)
2878 sum += double_bigit(n[i++]) * n[j--];
2879 bigits_[bigit_index] =
static_cast<bigit
>(sum);
2880 sum >>= num_bits<bigit>();
2882 remove_leading_zeros();
2888 FMTQUILL_CONSTEXPR
void align(
const bigint& other) {
2889 int exp_difference = exp_ - other.exp_;
2890 if (exp_difference <= 0)
return;
2891 int num_bigits =
static_cast<int>(bigits_.
size());
2892 bigits_.
resize(to_unsigned(num_bigits + exp_difference));
2893 for (
int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j)
2894 bigits_[j] = bigits_[i];
2895 fill_n(bigits_.
data(), to_unsigned(exp_difference), 0U);
2896 exp_ -= exp_difference;
2901 FMTQUILL_CONSTEXPR
auto divmod_assign(
const bigint& divisor) ->
int {
2902 FMTQUILL_ASSERT(
this != &divisor,
"");
2903 if (compare(*
this, divisor) < 0)
return 0;
2904 FMTQUILL_ASSERT(divisor.bigits_[divisor.bigits_.
size() - 1u] != 0,
"");
2908 subtract_aligned(divisor);
2910 }
while (compare(*
this, divisor) >= 0);
2917 predecessor_closer = 1,
2926 unsigned flags,
int num_digits,
2937 bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0;
2938 int shift = is_predecessor_closer ? 2 : 1;
2940 numerator = value.f;
2941 numerator <<= value.e + shift;
2944 if (is_predecessor_closer) {
2946 upper_store <<= value.e + 1;
2947 upper = &upper_store;
2949 denominator.assign_pow10(exp10);
2950 denominator <<= shift;
2951 }
else if (exp10 < 0) {
2952 numerator.assign_pow10(-exp10);
2953 lower.assign(numerator);
2954 if (is_predecessor_closer) {
2955 upper_store.assign(numerator);
2957 upper = &upper_store;
2959 numerator *= value.f;
2960 numerator <<= shift;
2962 denominator <<= shift - value.e;
2964 numerator = value.f;
2965 numerator <<= shift;
2966 denominator.assign_pow10(exp10);
2967 denominator <<= shift - value.e;
2969 if (is_predecessor_closer) {
2970 upper_store = 1ULL << 1;
2971 upper = &upper_store;
2974 int even =
static_cast<int>((value.f & 1) == 0);
2975 if (!upper) upper = &lower;
2976 bool shortest = num_digits < 0;
2977 if ((flags & dragon::fixup) != 0) {
2978 if (add_compare(numerator, *upper, denominator) + even <= 0) {
2981 if (num_digits < 0) {
2983 if (upper != &lower) *upper *= 10;
2986 if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1);
2992 char* data = buf.
data();
2994 int digit = numerator.divmod_assign(denominator);
2995 bool low = compare(numerator, lower) - even < 0;
2997 bool high = add_compare(numerator, *upper, denominator) + even > 0;
2998 data[num_digits++] =
static_cast<char>(
'0' + digit);
3001 ++data[num_digits - 1];
3003 int result = add_compare(numerator, numerator, denominator);
3005 if (result > 0 || (result == 0 && (digit % 2) != 0))
3006 ++data[num_digits - 1];
3008 buf.try_resize(to_unsigned(num_digits));
3009 exp10 -= num_digits - 1;
3014 if (upper != &lower) *upper *= 10;
3018 exp10 -= num_digits - 1;
3019 if (num_digits <= 0) {
3021 if (num_digits == 0) {
3023 digit = add_compare(numerator, numerator, denominator) > 0 ?
'1' :
'0';
3025 buf.push_back(digit);
3028 buf.try_resize(to_unsigned(num_digits));
3029 for (
int i = 0; i < num_digits - 1; ++i) {
3030 int digit = numerator.divmod_assign(denominator);
3031 buf[i] =
static_cast<char>(
'0' + digit);
3034 int digit = numerator.divmod_assign(denominator);
3035 auto result = add_compare(numerator, numerator, denominator);
3036 if (result > 0 || (result == 0 && (digit % 2) != 0)) {
3038 const auto overflow =
'0' + 10;
3039 buf[num_digits - 1] = overflow;
3041 for (
int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) {
3045 if (buf[0] == overflow) {
3047 if ((flags & dragon::fixed) != 0)
3056 buf[num_digits - 1] =
static_cast<char>(
'0' + digit);
3060 template <typename Float, FMTQUILL_ENABLE_IF(!is_double_double<Float>::value)>
3061 FMTQUILL_CONSTEXPR20
void format_hexfloat(Float value,
format_specs specs,
3065 static_assert(!std::is_same<Float, float>::value,
"");
3070 using carrier_uint =
typename info::carrier_uint;
3072 const auto num_float_significand_bits = detail::num_significand_bits<Float>();
3075 f.e += num_float_significand_bits;
3076 if (!has_implicit_bit<Float>()) --f.e;
3078 const auto num_fraction_bits =
3079 num_float_significand_bits + (has_implicit_bit<Float>() ? 1 : 0);
3080 const auto num_xdigits = (num_fraction_bits + 3) / 4;
3082 const auto leading_shift = ((num_xdigits - 1) * 4);
3083 const auto leading_mask = carrier_uint(0xF) << leading_shift;
3084 const auto leading_xdigit =
3085 static_cast<uint32_t
>((f.f & leading_mask) >> leading_shift);
3086 if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1);
3088 int print_xdigits = num_xdigits - 1;
3089 if (specs.precision >= 0 && print_xdigits > specs.precision) {
3090 const int shift = ((print_xdigits - specs.precision - 1) * 4);
3091 const auto mask = carrier_uint(0xF) << shift;
3092 const auto v =
static_cast<uint32_t
>((f.f & mask) >> shift);
3095 const auto inc = carrier_uint(1) << (shift + 4);
3101 if (!has_implicit_bit<Float>()) {
3102 const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
3103 if ((f.f & implicit_bit) == implicit_bit) {
3109 print_xdigits = specs.precision;
3112 char xdigits[num_bits<carrier_uint>() / 4];
3113 detail::fill_n(xdigits,
sizeof(xdigits),
'0');
3114 format_base2e(4, xdigits, f.f, num_xdigits, specs.upper());
3117 while (print_xdigits > 0 && xdigits[print_xdigits] ==
'0') --print_xdigits;
3120 buf.push_back(specs.upper() ?
'X' :
'x');
3121 buf.push_back(xdigits[0]);
3122 if (specs.alt() || print_xdigits > 0 || print_xdigits < specs.precision)
3124 buf.
append(xdigits + 1, xdigits + 1 + print_xdigits);
3125 for (; print_xdigits < specs.precision; ++print_xdigits) buf.push_back(
'0');
3127 buf.push_back(specs.upper() ?
'P' :
'p');
3132 abs_e =
static_cast<uint32_t
>(-f.e);
3135 abs_e =
static_cast<uint32_t
>(f.e);
3137 format_decimal<char>(
appender(buf), abs_e, detail::count_digits(abs_e));
3140 template <typename Float, FMTQUILL_ENABLE_IF(is_double_double<Float>::value)>
3141 FMTQUILL_CONSTEXPR20
void format_hexfloat(Float value,
format_specs specs,
3143 format_hexfloat(static_cast<double>(value), specs, buf);
3146 constexpr
auto fractional_part_rounding_thresholds(
int index) -> uint32_t {
3153 return U
"\x9999999a\x828f5c29\x80418938\x80068db9\x8000a7c6\x800010c7" 3154 U
"\x800001ae\x8000002b"[index];
3157 template <
typename Float>
3158 FMTQUILL_CONSTEXPR20
auto format_float(Float value,
int precision,
3162 static_assert(!std::is_same<Float, float>::value,
"");
3163 auto converted_value = convert_float(value);
3165 const bool fixed = specs.type() == presentation_type::fixed;
3167 if (precision <= 0 || !fixed) {
3171 buf.try_resize(to_unsigned(precision));
3172 fill_n(buf.
data(), precision,
'0');
3177 bool use_dragon =
true;
3178 unsigned dragon_flags = 0;
3180 const auto inv_log2_10 = 0.3010299956639812;
3187 auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10;
3188 exp =
static_cast<int>(e);
3190 dragon_flags = dragon::fixup;
3194 auto br = bit_cast<uint64_t>(
static_cast<double>(value));
3196 const uint64_t significand_mask =
3197 (
static_cast<uint64_t
>(1) << num_significand_bits<double>()) - 1;
3198 uint64_t significand = (br & significand_mask);
3199 int exponent =
static_cast<int>((br & exponent_mask<double>()) >>
3200 num_significand_bits<double>());
3202 if (exponent != 0) {
3203 exponent -= exponent_bias<double>() + num_significand_bits<double>();
3205 (
static_cast<uint64_t
>(1) << num_significand_bits<double>());
3209 FMTQUILL_ASSERT(significand != 0,
"zeros should not appear here");
3210 int shift = countl_zero(significand);
3211 FMTQUILL_ASSERT(shift >= num_bits<uint64_t>() - num_significand_bits<double>(),
3213 shift -= (num_bits<uint64_t>() - num_significand_bits<double>() - 2);
3214 exponent = (std::numeric_limits<double>::min_exponent -
3215 num_significand_bits<double>()) -
3217 significand <<= shift;
3222 const int k = info::kappa - dragonbox::floor_log10_pow2(exponent);
3224 const int beta = exponent + dragonbox::floor_log2_pow10(k);
3225 uint64_t first_segment;
3226 bool has_more_segments;
3227 int digits_in_the_first_segment;
3229 const auto r = dragonbox::umul192_upper128(
3230 significand << beta, dragonbox::get_cached_power(k));
3231 first_segment = r.high();
3232 has_more_segments = r.low() != 0;
3235 if (first_segment >= 1000000000000000000ULL) {
3236 digits_in_the_first_segment = 19;
3240 digits_in_the_first_segment = 18;
3241 first_segment *= 10;
3246 if (fixed) adjust_precision(precision, exp + digits_in_the_first_segment);
3250 if (digits_in_the_first_segment > precision) {
3253 if (precision <= 0) {
3254 exp += digits_in_the_first_segment;
3256 if (precision < 0) {
3262 if ((first_segment | static_cast<uint64_t>(has_more_segments)) >
3263 5000000000000000000ULL) {
3271 exp += digits_in_the_first_segment - precision;
3280 const uint32_t first_subsegment =
static_cast<uint32_t
>(
3281 dragonbox::umul128_upper64(first_segment, 7922816251426433760ULL) >>
3283 const uint64_t second_third_subsegments =
3284 first_segment - first_subsegment * 10000000000ULL;
3288 bool should_round_up;
3289 int number_of_digits_to_print = min_of(precision, 9);
3292 auto print_subsegment = [&](uint32_t subsegment,
char*
buffer) {
3293 int number_of_digits_printed = 0;
3296 if ((number_of_digits_to_print & 1) != 0) {
3302 prod = ((subsegment *
static_cast<uint64_t
>(720575941)) >> 24) + 1;
3303 digits =
static_cast<uint32_t
>(prod >> 32);
3304 *
buffer =
static_cast<char>(
'0' + digits);
3305 number_of_digits_printed++;
3315 prod = ((subsegment *
static_cast<uint64_t
>(450359963)) >> 20) + 1;
3316 digits =
static_cast<uint32_t
>(prod >> 32);
3317 write2digits(
buffer, digits);
3318 number_of_digits_printed += 2;
3322 while (number_of_digits_printed < number_of_digits_to_print) {
3323 prod =
static_cast<uint32_t
>(prod) * static_cast<uint64_t>(100);
3324 digits =
static_cast<uint32_t
>(prod >> 32);
3325 write2digits(
buffer + number_of_digits_printed, digits);
3326 number_of_digits_printed += 2;
3331 print_subsegment(first_subsegment, buf.
data());
3335 if (precision <= 9) {
3349 if (precision < 9) {
3350 uint32_t fractional_part =
static_cast<uint32_t
>(prod);
3352 fractional_part >= fractional_part_rounding_thresholds(
3353 8 - number_of_digits_to_print) ||
3354 ((fractional_part >> 31) &
3355 ((digits & 1) | (second_third_subsegments != 0) |
3356 has_more_segments)) != 0;
3364 should_round_up = second_third_subsegments > 5000000000ULL ||
3365 (second_third_subsegments == 5000000000ULL &&
3366 ((digits & 1) != 0 || has_more_segments));
3375 const uint32_t second_subsegment =
3376 static_cast<uint32_t
>(dragonbox::umul128_upper64(
3377 second_third_subsegments, 1844674407370955162ULL));
3378 const uint32_t third_subsegment =
3379 static_cast<uint32_t
>(second_third_subsegments) -
3380 second_subsegment * 10;
3382 number_of_digits_to_print = precision - 9;
3383 print_subsegment(second_subsegment, buf.
data() + 9);
3386 if (precision < 18) {
3390 uint32_t fractional_part =
static_cast<uint32_t
>(prod);
3392 fractional_part >= fractional_part_rounding_thresholds(
3393 8 - number_of_digits_to_print) ||
3394 ((fractional_part >> 31) &
3395 ((digits & 1) | (third_subsegment != 0) |
3396 has_more_segments)) != 0;
3403 should_round_up = third_subsegment > 5 ||
3404 (third_subsegment == 5 &&
3405 ((digits & 1) != 0 || has_more_segments));
3410 if (should_round_up) {
3411 ++buf[precision - 1];
3412 for (
int i = precision - 1; i > 0 && buf[i] >
'9'; --i) {
3419 buf[precision++] =
'0';
3424 buf.try_resize(to_unsigned(precision));
3429 exp += digits_in_the_first_segment - 1;
3434 bool is_predecessor_closer = binary32 ? f.assign(static_cast<float>(value))
3435 : f.assign(converted_value);
3436 if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer;
3437 if (fixed) dragon_flags |= dragon::fixed;
3440 const int max_double_digits = 767;
3441 if (precision > max_double_digits) precision = max_double_digits;
3442 format_dragon(f, dragon_flags, precision, buf, exp);
3444 if (!fixed && !specs.alt()) {
3446 auto num_digits = buf.
size();
3447 while (num_digits > 0 && buf[num_digits - 1] ==
'0') {
3451 buf.try_resize(num_digits);
3456 template <
typename Char,
typename OutputIt,
typename T,
3458 FMTQUILL_CONSTEXPR20
auto write(OutputIt out, T value,
format_specs specs,
3460 if (specs.localized() && write_loc(out, value, specs, loc))
return out;
3463 sign s = detail::signbit(value) ? sign::minus : specs.sign();
3465 if (!detail::isfinite(value))
3466 return write_nonfinite<Char>(out, detail::isnan(value), specs, s);
3468 if (specs.align() == align::numeric && s != sign::none) {
3469 *out++ = detail::getsign<Char>(s);
3471 if (specs.width != 0) --specs.width;
3474 const int exp_upper = detail::exp_upper<T>();
3475 int precision = specs.precision;
3476 if (precision < 0) {
3477 if (specs.type() != presentation_type::none) {
3481 auto dec = dragonbox::to_decimal(
static_cast<fast_float_t<T>
>(value));
3482 return write_float<Char>(out, dec, specs, s, exp_upper, loc);
3487 if (specs.type() == presentation_type::hexfloat) {
3488 if (s != sign::none) buffer.push_back(detail::getsign<char>(s));
3489 format_hexfloat(convert_float(value), specs, buffer);
3490 return write_bytes<Char, align::right>(out, {buffer.data(), buffer.size()},
3494 if (specs.type() == presentation_type::exp) {
3495 if (precision == max_value<int>())
3496 report_error(
"number is too big");
3499 if (specs.precision != 0) specs.set_alt();
3500 }
else if (specs.type() == presentation_type::fixed) {
3501 if (specs.precision != 0) specs.set_alt();
3502 }
else if (precision == 0) {
3505 int exp = format_float(convert_float(value), precision, specs,
3506 std::is_same<T, float>(), buffer);
3508 specs.precision = precision;
3509 auto f =
big_decimal_fp{buffer.data(),
static_cast<int>(buffer.size()), exp};
3510 return write_float<Char>(out, f, specs, s, exp_upper, loc);
3513 template <
typename Char,
typename OutputIt,
typename T,
3515 FMTQUILL_CONSTEXPR20
auto write(OutputIt out, T value) -> OutputIt {
3516 if (is_constant_evaluated())
return write<Char>(out, value,
format_specs());
3518 auto s = detail::signbit(value) ? sign::minus : sign::none;
3519 auto mask = exponent_mask<fast_float_t<T>>();
3520 if ((bit_cast<decltype(mask)>(value) & mask) == mask)
3521 return write_nonfinite<Char>(out, std::isnan(value), {}, s);
3523 auto dec = dragonbox::to_decimal(
static_cast<fast_float_t<T>
>(value));
3524 auto significand = dec.significand;
3525 int significand_size = count_digits(significand);
3526 int exponent = dec.exponent + significand_size - 1;
3527 if (use_fixed(exponent, detail::exp_upper<T>())) {
3528 return write_fixed<Char, fallback_digit_grouping<Char>>(
3529 out, dec, significand_size, Char(
'.'), {}, s);
3533 const char* prefix =
"e+";
3534 int abs_exponent = exponent;
3536 abs_exponent = -exponent;
3539 auto has_decimal_point = significand_size != 1;
3540 size_t size = std::is_pointer<OutputIt>::value
3542 : to_unsigned((s != sign::none ? 1 : 0) + significand_size +
3543 (has_decimal_point ? 1 : 0) +
3544 (abs_exponent >= 100 ? 5 : 4));
3545 if (
auto ptr = to_pointer<Char>(out, size)) {
3546 if (s != sign::none) *ptr++ = Char(
'-');
3547 if (has_decimal_point) {
3549 ptr = format_decimal<Char>(ptr, significand, significand_size + 1);
3553 *ptr++ =
static_cast<Char
>(
'0' + significand);
3555 if (std::is_same<Char, char>::value) {
3556 memcpy(ptr, prefix, 2);
3562 if (abs_exponent >= 100) {
3563 *ptr++ =
static_cast<Char
>(
'0' + abs_exponent / 100);
3564 abs_exponent %= 100;
3566 write2digits(ptr, static_cast<unsigned>(abs_exponent));
3567 return select<std::is_pointer<OutputIt>::value>(ptr + 2, out);
3569 auto it = reserve(out, size);
3570 if (s != sign::none) *it++ = Char(
'-');
3572 it = write_significand(it, significand, significand_size, 1,
3573 has_decimal_point ? Char(
'.') : Char());
3575 it = write_exponent<Char>(exponent, it);
3576 return base_iterator(out, it);
3579 template <
typename Char,
typename OutputIt,
typename T,
3582 inline auto write(OutputIt out, T value) -> OutputIt {
3583 return write<Char>(out, value, {});
3586 template <
typename Char,
typename OutputIt>
3589 FMTQUILL_ASSERT(
false,
"");
3593 template <
typename Char,
typename OutputIt>
3596 return copy_noinline<Char>(value.begin(), value.end(), out);
3599 template <
typename Char,
typename OutputIt,
typename T,
3601 constexpr
auto write(OutputIt out,
const T& value) -> OutputIt {
3602 return write<Char>(out, to_string_view(value));
3607 typename Char,
typename OutputIt,
typename T,
3608 bool check = std::is_enum<T>::value && !std::is_same<T, Char>::value &&
3610 FMTQUILL_ENABLE_IF(check)>
3611 FMTQUILL_CONSTEXPR
auto write(OutputIt out, T value) -> OutputIt {
3612 return write<Char>(out,
static_cast<underlying_t<T>
>(value));
3615 template <
typename Char,
typename OutputIt,
typename T,
3616 FMTQUILL_ENABLE_IF(std::is_same<T, bool>::value)>
3617 FMTQUILL_CONSTEXPR
auto write(OutputIt out, T value,
const format_specs& specs = {},
3619 return specs.type() != presentation_type::none &&
3620 specs.type() != presentation_type::string
3621 ? write<Char>(out, value ? 1 : 0, specs, {})
3622 : write_bytes<Char>(out, value ?
"true" :
"false", specs);
3625 template <
typename Char,
typename OutputIt>
3626 FMTQUILL_CONSTEXPR
auto write(OutputIt out, Char value) -> OutputIt {
3627 auto it = reserve(out, 1);
3629 return base_iterator(out, it);
3632 template <
typename Char,
typename OutputIt>
3633 FMTQUILL_CONSTEXPR20
auto write(OutputIt out,
const Char* value) -> OutputIt {
3635 report_error(
"string pointer is null");
3639 template <
typename Char,
typename OutputIt,
typename T,
3640 FMTQUILL_ENABLE_IF(std::is_same<T, void>::value)>
3641 auto write(OutputIt out,
const T* value,
const format_specs& specs = {},
3643 return write_ptr<Char>(out, bit_cast<uintptr_t>(value), &specs);
3646 template <
typename Char,
typename OutputIt,
typename T,
3648 type::custom_type &&
3649 !std::is_fundamental<T>::value)>
3650 FMTQUILL_CONSTEXPR
auto write(OutputIt out,
const T& value) -> OutputIt {
3654 auto ctx = basic_format_context<OutputIt, Char>(out, {}, {});
3655 return f.format(value, ctx);
3658 template <
typename T>
3660 bool_constant<std::is_same<T, int>::value || FMTQUILL_BUILTIN_TYPES>;
3665 using context = buffered_context<Char>;
3669 void operator()(
monostate) { report_error(
"argument not found"); }
3671 template <typename T, FMTQUILL_ENABLE_IF(is_builtin<T>::value)>
3672 void operator()(T value) {
3673 write<Char>(out, value);
3676 template <typename T, FMTQUILL_ENABLE_IF(!is_builtin<T>::value)>
3677 void operator()(T) {
3678 FMTQUILL_ASSERT(
false,
"");
3684 auto format_ctx =
context(out, {}, {});
3685 h.format(parse_ctx, format_ctx);
3692 FMTQUILL_NO_UNIQUE_ADDRESS
locale_ref locale;
3694 template <typename T, FMTQUILL_ENABLE_IF(is_builtin<T>::value)>
3695 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
void operator()(T value) {
3696 detail::write<Char>(out, value, specs, locale);
3699 template <typename T, FMTQUILL_ENABLE_IF(!is_builtin<T>::value)>
3700 void operator()(T) {
3701 FMTQUILL_ASSERT(
false,
"");
3704 void operator()(
typename basic_format_arg<buffered_context<Char>>::handle) {
3711 template <typename T, FMTQUILL_ENABLE_IF(is_integer<T>::value)>
3712 FMTQUILL_CONSTEXPR
auto operator()(T value) ->
unsigned long long {
3713 return is_negative(value) ? ~0ull :
static_cast<unsigned long long>(value);
3716 template <typename T, FMTQUILL_ENABLE_IF(!is_integer<T>::value)>
3717 FMTQUILL_CONSTEXPR
auto operator()(T) ->
unsigned long long {
3718 report_error(
"width/precision is not integer");
3723 template <
typename Context>
3724 FMTQUILL_CONSTEXPR
void handle_dynamic_spec(
3725 arg_id_kind kind,
int& value,
3727 if (kind == arg_id_kind::none)
return;
3729 kind == arg_id_kind::index ? ctx.arg(ref.index) : ctx.arg(ref.name);
3730 if (!arg) report_error(
"argument not found");
3732 if (result > to_unsigned(max_value<int>()))
3733 report_error(
"width/precision is out of range");
3734 value =
static_cast<int>(result);
3737 #if FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 3738 template <
typename T,
typename Char,
size_t N,
3739 fmtquill::detail::fixed_string<Char, N> Str>
3740 struct static_named_arg :
view {
3741 static constexpr
auto name = Str.data;
3744 static_named_arg(
const T& v) : value(v) {}
3747 template <
typename T,
typename Char,
size_t N,
3748 fmtquill::detail::fixed_string<Char, N> Str>
3749 struct is_named_arg<static_named_arg<T, Char, N, Str>> : std::true_type {};
3751 template <
typename T,
typename Char,
size_t N,
3752 fmtquill::detail::fixed_string<Char, N> Str>
3756 template <
typename Char,
size_t N, fmtquill::detail::fixed_
string<Char, N> Str>
3758 template <
typename T>
auto operator=(T&& value)
const {
3759 return static_named_arg<T, Char, N, Str>(std::forward<T>(value));
3767 return {str, std::forward<T>(value)};
3770 #endif // FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 3774 buffered_context<Char> ctx;
3776 void on_text(
const Char* begin,
const Char* end) {
3777 copy_noinline<Char>(begin, end, ctx.out());
3780 FMTQUILL_CONSTEXPR
auto on_arg_id() ->
int {
return parse_ctx.next_arg_id(); }
3781 FMTQUILL_CONSTEXPR
auto on_arg_id(
int id) ->
int {
3782 parse_ctx.check_arg_id(
id);
3786 parse_ctx.check_arg_id(
id);
3787 int arg_id = ctx.arg_id(
id);
3788 if (arg_id < 0) report_error(
"argument not found");
3792 FMTQUILL_INLINE
void on_replacement_field(
int id,
const Char*) {
3796 auto on_format_specs(
int id,
const Char* begin,
const Char* end)
3798 auto arg = ctx.arg(
id);
3799 if (!arg) report_error(
"argument not found");
3801 if (arg.format_custom(begin, parse_ctx, ctx))
return parse_ctx.begin();
3804 begin = parse_format_specs(begin, end, specs, parse_ctx, arg.type());
3805 if (specs.dynamic()) {
3806 handle_dynamic_spec(specs.dynamic_width(), specs.width, specs.width_ref,
3808 handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
3809 specs.precision_ref, ctx);
3816 FMTQUILL_NORETURN
void on_error(
const char* message) { report_error(message); }
3821 FMTQUILL_API
void do_report_error(format_func func,
int error_code,
3822 const char* message) noexcept;
3824 FMTQUILL_API
void format_error_code(
buffer<char>& out,
int error_code,
3827 template <
typename T,
typename Char, type TYPE>
3828 template <
typename FormatContext>
3830 const T& val, FormatContext& ctx)
const -> decltype(ctx.out()) {
3831 if (!specs_.dynamic())
3832 return write<Char>(ctx.out(), val, specs_, ctx.locale());
3834 handle_dynamic_spec(specs.dynamic_width(), specs.width, specs_.width_ref,
3836 handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
3837 specs_.precision_ref, ctx);
3838 return write<Char>(ctx.out(), val, specs, ctx.locale());
3842 FMTQUILL_BEGIN_EXPORT
3854 using char_type = Char;
3855 using iterator = OutputIt;
3856 enum { builtin_types = FMTQUILL_BUILTIN_TYPES };
3861 : out_(out), args_(args), loc_(loc) {}
3867 return args_.
get(
id);
3871 return args_.
get(name);
3874 return args_.get_id(name);
3877 constexpr
auto out()
const -> iterator {
return out_; }
3879 void advance_to(iterator it) {
3883 constexpr
auto locale()
const ->
locale_ref {
return loc_; }
3891 template <typename T, FMTQUILL_ENABLE_IF(!detail::is_float128<T>::value)>
3894 template <typename T, FMTQUILL_ENABLE_IF(detail::is_float128<T>::value)>
3897 template <
typename Visitor>
auto visit(Visitor&& vis) -> decltype(vis(0)) {
3898 return value_.
visit(vis);
3906 std::string separator_;
3907 std::string grouping_;
3908 std::string decimal_point_;
3915 static FMTQUILL_API
typename Locale::id id;
3919 std::string decimal_point =
".")
3920 : separator_(sep.data(), sep.size()),
3921 grouping_(grouping),
3922 decimal_point_(decimal_point) {}
3926 return do_put(out, val, specs);
3930 #define FMTQUILL_FORMAT_AS(Type, Base) \ 3931 template <typename Char> \ 3932 struct formatter<Type, Char> : formatter<Base, Char> { \ 3933 template <typename FormatContext> \ 3934 FMTQUILL_CONSTEXPR auto format(Type value, FormatContext& ctx) const \ 3935 -> decltype(ctx.out()) { \ 3936 return formatter<Base, Char>::format(value, ctx); \ 3940 FMTQUILL_FORMAT_AS(
signed char,
int);
3941 FMTQUILL_FORMAT_AS(
unsigned char,
unsigned);
3942 FMTQUILL_FORMAT_AS(
short,
int);
3943 FMTQUILL_FORMAT_AS(
unsigned short,
unsigned);
3944 FMTQUILL_FORMAT_AS(
long, detail::long_type);
3945 FMTQUILL_FORMAT_AS(
unsigned long, detail::ulong_type);
3946 FMTQUILL_FORMAT_AS(Char*,
const Char*);
3948 FMTQUILL_FORMAT_AS(std::nullptr_t,
const void*);
3949 FMTQUILL_FORMAT_AS(
void*,
const void*);
3951 template <
typename Char,
size_t N>
3954 template <
typename Char,
typename Traits,
typename Allocator>
3955 class formatter<std::basic_string<Char, Traits, Allocator>, Char>
3956 :
public formatter<basic_string_view<Char>, Char> {};
3958 template <
int N,
typename Char>
3960 template <
int N,
typename Char>
3962 :
formatter<unsigned long long, Char> {};
3964 template <
typename Char>
3967 detail::type::float_type> {};
3969 template <
typename T,
typename Char>
3970 struct formatter<T, Char, void_t<detail::format_as_result<T>>>
3971 :
formatter<detail::format_as_result<T>, Char> {
3972 template <
typename FormatContext>
3973 FMTQUILL_CONSTEXPR
auto format(
const T& value, FormatContext& ctx)
const 3974 -> decltype(ctx.out()) {
3975 auto&& val = format_as(value);
3987 template <
typename T>
auto ptr(T p) ->
const void* {
3988 static_assert(std::is_pointer<T>::value,
"fmtquill::ptr used with non-pointer");
3989 return detail::bit_cast<
const void*>(p);
4000 template <
typename Enum>
4001 constexpr
auto underlying(Enum e) noexcept -> underlying_t<Enum> {
4002 return static_cast<underlying_t<Enum>
>(e);
4006 template <typename Enum, FMTQUILL_ENABLE_IF(std::is_enum<Enum>::value)>
4007 constexpr
auto format_as(Enum e) noexcept -> underlying_t<Enum> {
4008 return static_cast<underlying_t<Enum>
>(e);
4012 #ifdef __cpp_lib_byte 4013 template <
typename Char>
4015 static auto format_as(std::byte b) ->
unsigned char {
4016 return static_cast<unsigned char>(b);
4018 template <
typename Context>
4019 auto format(std::byte b, Context& ctx)
const -> decltype(ctx.out()) {
4037 return parse_format_specs(ctx.
begin(), ctx.
end(), specs_, ctx,
4038 detail::type::string_type);
4041 template <
typename FormatContext>
4042 auto format(
bytes b, FormatContext& ctx)
const -> decltype(ctx.out()) {
4043 auto specs = specs_;
4044 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
4045 specs.width_ref, ctx);
4046 detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
4047 specs.precision_ref, ctx);
4048 return detail::write_bytes<char>(ctx.out(), b.data, specs);
4076 return parse_format_specs(ctx.
begin(), ctx.
end(), specs_, ctx,
4077 detail::type::int_type);
4080 template <
typename FormatContext>
4082 -> decltype(ctx.out()) {
4083 auto specs = specs_;
4084 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
4085 specs.width_ref, ctx);
4086 detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
4087 specs.precision_ref, ctx);
4088 auto arg = detail::make_write_int_arg(view.value, specs.sign());
4089 return detail::write_int(
4090 ctx.out(),
static_cast<detail::uint64_or_128_t<T>
>(arg.abs_value),
4100 template <
typename T,
typename Char>
4105 template <
typename FormatContext>
4107 -> decltype(ctx.out()) {
4108 return view.fmt->format(*view.value, ctx);
4122 auto it = ctx.
begin(), end = ctx.
end();
4123 if (it == end)
return it;
4125 it = detail::parse_align(it, end, specs);
4129 if ((c >=
'0' && c <=
'9') || c ==
'{') {
4130 it = detail::parse_width(it, end, specs, width_ref, ctx);
4131 width_ = specs.width;
4134 return formatter_.parse(ctx);
4137 template <
typename FormatContext,
typename F>
4138 auto write_padded(FormatContext& ctx, F write)
const -> decltype(ctx.out()) {
4139 if (width_ == 0)
return write(ctx.out());
4143 specs.width = width_;
4144 specs.copy_fill_from(specs_);
4145 specs.set_align(specs_.align());
4146 return detail::write<Char>(
4156 #if FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 4157 template <detail::fixed_
string S> constexpr
auto operator""_a() {
4158 using char_t = remove_cvref_t<decltype(*S.data)>;
4173 #endif // FMTQUILL_USE_NONTYPE_TEMPLATE_ARGS 4181 enum { buffer_size = std::numeric_limits<unsigned long long>::digits10 + 3 };
4182 mutable char buffer_[buffer_size];
4185 template <
typename UInt>
4186 FMTQUILL_CONSTEXPR20
auto format_unsigned(UInt value) ->
char* {
4187 auto n =
static_cast<detail::uint32_or_64_or_128_t<UInt>
>(value);
4188 return detail::do_format_decimal(buffer_, n, buffer_size - 1);
4191 template <
typename Int>
4192 FMTQUILL_CONSTEXPR20
auto format_signed(Int value) ->
char* {
4193 auto abs_value =
static_cast<detail::uint32_or_64_or_128_t<Int>
>(value);
4194 bool negative = value < 0;
4195 if (negative) abs_value = 0 - abs_value;
4196 auto begin = format_unsigned(abs_value);
4197 if (negative) *--begin =
'-';
4202 FMTQUILL_CONSTEXPR20
explicit format_int(
int value) : str_(format_signed(value)) {}
4203 FMTQUILL_CONSTEXPR20
explicit format_int(
long value)
4204 : str_(format_signed(value)) {}
4205 FMTQUILL_CONSTEXPR20
explicit format_int(
long long value)
4206 : str_(format_signed(value)) {}
4207 FMTQUILL_CONSTEXPR20
explicit format_int(
unsigned value)
4208 : str_(format_unsigned(value)) {}
4209 FMTQUILL_CONSTEXPR20
explicit format_int(
unsigned long value)
4210 : str_(format_unsigned(value)) {}
4211 FMTQUILL_CONSTEXPR20
explicit format_int(
unsigned long long value)
4212 : str_(format_unsigned(value)) {}
4215 FMTQUILL_CONSTEXPR20
auto size() const ->
size_t {
4216 return detail::to_unsigned(buffer_ - str_ + buffer_size - 1);
4221 FMTQUILL_CONSTEXPR20
auto data() const -> const
char* {
return str_; }
4225 FMTQUILL_CONSTEXPR20
auto c_str() const -> const
char* {
4226 buffer_[buffer_size - 1] =
'\0';
4231 inline auto str() const -> std::
string {
return {str_, size()}; }
4234 #if FMTQUILL_CLANG_ANALYZER 4235 # define FMTQUILL_STRING_IMPL(s, base) s 4237 # define FMTQUILL_STRING_IMPL(s, base) \ 4241 struct FMTQUILL_VISIBILITY("hidden") FMTQUILL_COMPILE_STRING : base { \ 4242 using char_type = fmtquill::remove_cvref_t<decltype(s[0])>; \ 4243 constexpr explicit operator fmtquill::basic_string_view<char_type>() \ 4245 return fmtquill::detail::compile_string_to_view<char_type>(s); \ 4248 using FMTQUILL_STRING_VIEW = \ 4249 fmtquill::basic_string_view<typename FMTQUILL_COMPILE_STRING::char_type>; \ 4250 fmtquill::detail::ignore_unused(FMTQUILL_STRING_VIEW(FMTQUILL_COMPILE_STRING())); \ 4251 return FMTQUILL_COMPILE_STRING(); \ 4253 #endif // FMTQUILL_CLANG_ANALYZER 4263 #define FMTQUILL_STRING(s) FMTQUILL_STRING_IMPL(s, fmtquill::detail::compile_string) 4266 -> std::system_error;
4283 template <
typename... T>
4284 auto system_error(
int error_code, format_string<T...> fmt, T&&... args)
4285 -> std::system_error {
4286 return vsystem_error(error_code, fmt.str,
vargs<T...>{{args...}});
4303 const char* message) noexcept;
4307 FMTQUILL_API
void report_system_error(
int error_code,
const char* message) noexcept;
4312 detail::vformat_to(buf, fmt, args, loc);
4316 template <
typename... T>
4317 FMTQUILL_INLINE
auto format(
locale_ref loc, format_string<T...> fmt, T&&... args)
4319 return vformat(loc, fmt.str,
vargs<T...>{{args...}});
4322 template <
typename OutputIt,
4326 auto&& buf = detail::get_buffer<char>(out);
4327 detail::vformat_to(buf, fmt, args, loc);
4328 return detail::get_iterator(buf, out);
4331 template <
typename OutputIt,
typename... T,
4333 FMTQUILL_INLINE
auto format_to(OutputIt out,
locale_ref loc, format_string<T...> fmt,
4334 T&&... args) -> OutputIt {
4335 return fmtquill::vformat_to(out, loc, fmt.str,
vargs<T...>{{args...}});
4338 template <
typename... T>
4339 FMTQUILL_NODISCARD FMTQUILL_INLINE
auto formatted_size(
locale_ref loc,
4340 format_string<T...> fmt,
4341 T&&... args) ->
size_t {
4343 detail::vformat_to(buf, fmt.str,
vargs<T...>{{args...}}, loc);
4358 template <
typename... T>
4359 FMTQUILL_NODISCARD FMTQUILL_INLINE
auto format(format_string<T...> fmt, T&&... args)
4371 template <typename T, FMTQUILL_ENABLE_IF(std::is_integral<T>::value)>
4372 FMTQUILL_NODISCARD FMTQUILL_CONSTEXPR_STRING
auto to_string(T value) -> std::string {
4375 char buffer[max_of(detail::digits10<T>() + 2, 5)];
4376 return {buffer, detail::write<char>(buffer, value)};
4379 template <typename T, FMTQUILL_ENABLE_IF(detail::use_format_as<T>::value)>
4380 FMTQUILL_NODISCARD FMTQUILL_CONSTEXPR_STRING
auto to_string(
const T& value)
4382 return to_string(format_as(value));
4385 template <typename T, FMTQUILL_ENABLE_IF(!std::is_integral<T>::value &&
4387 FMTQUILL_NODISCARD FMTQUILL_CONSTEXPR_STRING
auto to_string(
const T& value)
4390 detail::write<char>(
appender(buffer), value);
4391 return {buffer.data(), buffer.size()};
4395 FMTQUILL_END_NAMESPACE
4397 #ifdef FMTQUILL_HEADER_ONLY 4398 # define FMTQUILL_FUNC inline 4399 # include "format-inl.h" 4403 #ifdef FMTQUILL_REMOVE_TRANSITIVE_INCLUDES 4404 # undef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES 4407 #if defined(__GNUC__) || defined(__clang__) || defined(__MINGW32__) 4408 #pragma GCC diagnostic pop 4411 #endif // FMTQUILL_FORMAT_H_ Definition: format.h:4053
Definition: format.h:2633
A dynamically growing memory buffer for trivially copyable/constructible types with the first SIZE el...
Definition: format.h:809
FMTQUILL_CONSTEXPR auto data() noexcept -> T *
Returns a pointer to the buffer data (not null-terminated).
Definition: base.h:1825
void reserve(size_t new_capacity)
Increases the buffer capacity to new_capacity.
Definition: format.h:922
Definition: format.h:4025
Definition: format.h:2031
FMTQUILL_CONSTEXPR void set(T *buf_data, size_t buf_capacity) noexcept
Sets the buffer data and capacity.
Definition: base.h:1800
Definition: format.h:2495
Definition: format.h:1880
Definition: format.h:3886
Definition: format.h:2053
Definition: format.h:2011
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition: base.h:634
Definition: LogFunctions.h:198
Definition: UserDefinedDirectFormatFuzzer.cpp:81
FMTQUILL_CONSTEXPR20 void append(const U *begin, const U *end)
Appends data to the end of the buffer.
Definition: base.h:1859
constexpr auto data() const noexcept -> const Char *
Returns a pointer to the string data.
Definition: base.h:568
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:901
Definition: format.h:3710
Definition: format.h:1171
FMTQUILL_CONSTEXPR void advance_to(iterator it)
Advances the begin iterator to it.
Definition: base.h:886
constexpr auto size() const noexcept -> size_t
Returns the string size.
Definition: base.h:571
Definition: format.h:1478
Definition: LogFunctions.h:261
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:526
Definition: format.h:1577
FMTQUILL_CONSTEXPR void clear()
Clears this buffer.
Definition: base.h:1829
constexpr auto end() const noexcept -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition: base.h:883
constexpr auto size() const noexcept -> size_t
Returns the size of this buffer.
Definition: base.h:1819
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:956
Definition: format.h:1464
Definition: format.h:4095
Definition: format.h:1329
Definition: format.h:2379
constexpr auto capacity() const noexcept -> size_t
Returns the capacity of this buffer.
Definition: base.h:1822
Definition: format.h:1758
Definition: format.h:4155
constexpr auto begin() const noexcept -> iterator
Returns an iterator to the beginning of the format string range being parsed.
Definition: base.h:880
Definition: doctest.h:526
Definition: format.h:2675
Definition: format.h:1312
Definition: format.h:4005
Definition: format.h:3763
A contiguous memory buffer with an optional growing ability.
Definition: base.h:1777
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:907
FMTQUILL_CONSTEXPR void resize(size_t count)
Resizes the buffer to contain count elements.
Definition: format.h:919
Definition: format.h:1505