namespace std { template <class T> struct iterator_traits<fmt::basic_appender<T>> { using iterator_category = output_iterator_tag; using value_type = T; using difference_type =
decltype(static_cast<int*>(nullptr) - static_cast<int*>(nullptr)); using pointer = void; using reference = void;
};
} // namespace std
#ifndef FMT_THROW # if FMT_USE_EXCEPTIONS # if FMT_MSC_VERSION || defined(__NVCC__)
FMT_BEGIN_NAMESPACE namespace detail { template <typename Exception> inlinevoid do_throw(const Exception& x) { // Silence unreachable code warnings in MSVC and NVCC because these // are nearly impossible to fix in a generic code. volatilebool b = true; if (b) throw x;
}
} // namespace detail
FMT_END_NAMESPACE # define FMT_THROW(x) detail::do_throw(x) # else # define FMT_THROW(x) throw x # endif # else # define FMT_THROW(x) \
::fmt::detail::assert_fail(__FILE__, __LINE__, (x).what()) # endif #endif
#ifdef FMT_NO_UNIQUE_ADDRESS // Use the provided definition. #elif FMT_CPLUSPLUS < 202002L // Not supported. #elif FMT_HAS_CPP_ATTRIBUTE(no_unique_address) # define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]] // VS2019 v16.10 and later except clang-cl (https://reviews.llvm.org/D110485). #elif FMT_MSC_VERSION >= 1929 && !FMT_CLANG_VERSION # define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] #endif #ifndef FMT_NO_UNIQUE_ADDRESS # define FMT_NO_UNIQUE_ADDRESS #endif
// Defining FMT_REDUCE_INT_INSTANTIATIONS to 1, will reduce the number of // integer formatter template instantiations to just one by only using the // largest integer type. This results in a reduction in binary size but will // cause a decrease in integer formatting performance. #if !defined(FMT_REDUCE_INT_INSTANTIATIONS) # define FMT_REDUCE_INT_INSTANTIATIONS 0 #endif
// __builtin_clz is broken in clang with Microsoft codegen: // https://github.com/fmtlib/fmt/issues/519. #if !FMT_MSC_VERSION # if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION # define FMT_BUILTIN_CLZ(n) __builtin_clz(n) # endif # if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) # endif #endif
// __builtin_ctz is broken in Intel Compiler Classic on Windows: // https://github.com/fmtlib/fmt/issues/2510. #ifndef __ICL # if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION || \ defined(__NVCOMPILER) # define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) # endif # if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || \
FMT_ICC_VERSION || defined(__NVCOMPILER) # define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) # endif #endif
// Some compilers masquerade as both MSVC and GCC-likes or otherwise support // __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the // MSVC intrinsics if the clz and clzll builtins are not available. #if FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) && \
!defined(FMT_BUILTIN_CTZLL)
FMT_BEGIN_NAMESPACE namespace detail { // Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. # if !defined(__clang__) # pragma intrinsic(_BitScanForward) # pragma intrinsic(_BitScanReverse) # ifdefined(_WIN64) # pragma intrinsic(_BitScanForward64) # pragma intrinsic(_BitScanReverse64) # endif # endif
inlineauto clz(uint32_t x) -> int { unsignedlong r = 0;
_BitScanReverse(&r, x);
FMT_ASSERT(x != 0, ""); // Static analysis complains about using uninitialized data // "r", but the only way that can happen is if "x" is 0, // which the callers guarantee to not happen.
FMT_MSC_WARNING(suppress : 6102) return31 ^ static_cast<int>(r);
} # define FMT_BUILTIN_CLZ(n) detail::clz(n)
inlineauto clzll(uint64_t x) -> int { unsignedlong r = 0; # ifdef _WIN64
_BitScanReverse64(&r, x); # else // Scan the high 32 bits. if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32))) return63 ^ static_cast<int>(r + 32); // Scan the low 32 bits.
_BitScanReverse(&r, static_cast<uint32_t>(x)); # endif
FMT_ASSERT(x != 0, "");
FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. return63 ^ static_cast<int>(r);
} # define FMT_BUILTIN_CLZLL(n) detail::clzll(n)
// Implementation of std::bit_cast for pre-C++20. template <typename To, typename From, FMT_ENABLE_IF(sizeof(To) == sizeof(From))>
FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To { #ifdef __cpp_lib_bit_cast if (is_constant_evaluated()) return std::bit_cast<To>(from); #endif auto to = To(); // The cast suppresses a bogus -Wclass-memaccess on GCC.
std::memcpy(static_cast<void*>(&to), &from, sizeof(to)); return to;
}
using uint128_t = conditional_t<FMT_USE_INT128, uint128_opt, uint128_fallback>;
#ifdef UINTPTR_MAX using uintptr_t = ::uintptr_t; #else using uintptr_t = uint128_t; #endif
// Returns the largest possible value for type T. Same as // std::numeric_limits<T>::max() but shorter and not affected by the max macro. template <typename T> constexpr auto max_value() -> T { return (std::numeric_limits<T>::max)();
} template <typename T> constexpr auto num_bits() -> int { return std::numeric_limits<T>::digits;
} // std::numeric_limits<T>::digits may return 0 for 128-bit ints. template <> constexpr auto num_bits<int128_opt>() -> int { return128; } template <> constexpr auto num_bits<uint128_opt>() -> int { return128; } template <> constexpr auto num_bits<uint128_fallback>() -> int { return128; }
// A heterogeneous bit_cast used for converting 96-bit long double to uint128_t // and 128-bit pointers to uint128_fallback. template <typename To, typename From, FMT_ENABLE_IF(sizeof(To) > sizeof(From))> inlineauto bit_cast(const From& from) -> To {
constexpr auto size = static_cast<int>(sizeof(From) / sizeof(unsigned)); struct data_t { unsigned value[static_cast<unsigned>(size)];
} data = bit_cast<data_t>(from); auto result = To(); if (const_check(is_big_endian())) { for (int i = 0; i < size; ++i)
result = (result << num_bits<unsigned>()) | data.value[i];
} else { for (int i = size - 1; i >= 0; --i)
result = (result << num_bits<unsigned>()) | data.value[i];
} return result;
}
template <typename UInt>
FMT_CONSTEXPR20 inlineauto countl_zero_fallback(UInt n) -> int { int lz = 0;
constexpr UInt msb_mask = static_cast<UInt>(1) << (num_bits<UInt>() - 1); for (; (n & msb_mask) == 0; n <<= 1) lz++; return lz;
}
FMT_CONSTEXPR20 inlineauto countl_zero(uint32_t n) -> int { #ifdef FMT_BUILTIN_CLZ if (!is_constant_evaluated()) return FMT_BUILTIN_CLZ(n); #endif return countl_zero_fallback(n);
}
FMT_CONSTEXPR20 inlineauto countl_zero(uint64_t n) -> int { #ifdef FMT_BUILTIN_CLZLL if (!is_constant_evaluated()) return FMT_BUILTIN_CLZLL(n); #endif return countl_zero_fallback(n);
}
// Attempts to reserve space for n extra characters in the output range. // Returns a pointer to the reserved range or a reference to it. template <typename OutputIt,
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value&&
is_contiguous<typename OutputIt::container>::value)> #if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION
__attribute__((no_sanitize("undefined"))) #endif
FMT_CONSTEXPR20 inlineauto
reserve(OutputIt it, size_t n) -> typename OutputIt::value_type* { auto& c = get_container(it);
size_t size = c.size();
c.resize(size + n); return &c[size];
}
// A public domain branchless UTF-8 decoder by Christopher Wellons: // https://github.com/skeeto/branchless-utf8 /* Decode the next character, c, from s, reporting errors in e. * *Sincethisisabranchlessdecoder,fourbyteswillbereadfromthe *bufferregardlessoftheactuallengthofthenextcharacter.This *meansthebuffer_must_haveatleastthreebytesofzeropadding *followingtheendofthedatastream. * *Errorsarereportedine,whichwillbenon-zeroiftheparsed *characterwassomehowinvalid:invalidbytesequence,non-canonical *encoding,orasurrogatehalf. * *Thefunctionreturnsapointertothenextcharacter.Whenanerror *occurs,thispointerwillbeaguessthatdependsontheparticular *error,butitwillalwaysadvanceatleastonebyte.
*/
FMT_CONSTEXPR inlineauto utf8_decode(constchar* s, uint32_t* c, int* e)
-> constchar* {
constexpr constint masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
constexpr constint shiftc[] = {0, 18, 12, 6, 0};
constexpr constint shifte[] = {0, 6, 4, 2, 0};
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"
[static_cast<unsignedchar>(*s) >> 3]; // Compute the pointer to the next character early so that the next // iteration can start working on the next character. Neither Clang // nor GCC figure out this reordering on their own. constchar* next = s + len + !len;
using uchar = unsignedchar;
// Assume a four-byte character and load four bytes. Unused bits are // shifted out.
*c = uint32_t(uchar(s[0]) & masks[len]) << 18;
*c |= uint32_t(uchar(s[1]) & 0x3f) << 12;
*c |= uint32_t(uchar(s[2]) & 0x3f) << 6;
*c |= uint32_t(uchar(s[3]) & 0x3f) << 0;
*c >>= shiftc[len];
// Accumulate the various error conditions.
*e = (*c < mins[len]) << 6; // non-canonical encoding
*e |= ((*c >> 11) == 0x1b) << 7; // surrogate half?
*e |= (*c > 0x10FFFF) << 8; // out of range?
*e |= (uchar(s[1]) & 0xc0) >> 2;
*e |= (uchar(s[2]) & 0xc0) >> 4;
*e |= uchar(s[3]) >> 6;
*e ^= 0x2a; // top two bits of each tail byte correct?
*e >>= shifte[len];
// Invokes f(cp, sv) for every code point cp in s with sv being the string view // corresponding to the code point. cp is invalid_code_point on error. template <typename F>
FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) { auto decode = [f](constchar* buf_ptr, constchar* ptr) { auto cp = uint32_t(); auto error = 0; auto end = utf8_decode(buf_ptr, &cp, &error); bool result = f(error ? invalid_code_point : cp,
string_view(ptr, error ? 1 : to_unsigned(end - buf_ptr))); return result ? (error ? buf_ptr + 1 : end) : nullptr;
};
auto p = s.data(); const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. if (s.size() >= block_size) { for (auto end = p + s.size() - block_size + 1; p < end;) {
p = decode(p, p); if (!p) return;
}
} auto num_chars_left = to_unsigned(s.data() + s.size() - p); if (num_chars_left == 0) return;
FMT_ASSERT(num_chars_left < block_size, ""); char buf[2 * block_size - 1] = {};
copy<char>(p, p + num_chars_left, buf); constchar* buf_ptr = buf; do { auto end = decode(buf_ptr, p); if (!end) return;
p += end - buf_ptr;
buf_ptr = end;
} while (buf_ptr < buf + num_chars_left);
}
// Calculates the index of the nth code point in a UTF-8 string. inlineauto code_point_index(string_view s, size_t n) -> size_t {
size_t result = s.size(); constchar* begin = s.begin();
for_each_codepoint(s, [begin, &n, &result](uint32_t, string_view sv) { if (n != 0) {
--n; returntrue;
}
result = to_unsigned(sv.begin() - begin); returnfalse;
}); return result;
}
// An allocator that uses malloc/free to allow removing dependency on the C++ // standard libary runtime. template <typename T> struct allocator { using value_type = T;
// The number of characters to store in the basic_memory_buffer object itself // to avoid dynamic memory allocation. enum { inline_buffer_size = 500 };
// Don't inherit from Allocator to avoid generating type_info for it.
FMT_NO_UNIQUE_ADDRESS Allocator alloc_;
// Deallocate memory allocated by the buffer.
FMT_CONSTEXPR20 void deallocate() {
T* data = this->data(); if (data != store_) alloc_.deallocate(data, this->capacity());
}
static FMT_CONSTEXPR20 void grow(detail::buffer<T>& buf, size_t size) {
detail::abort_fuzzing_if(size > 5000); auto& self = static_cast<basic_memory_buffer&>(buf); const size_t max_size =
std::allocator_traits<Allocator>::max_size(self.alloc_);
size_t old_capacity = buf.capacity();
size_t new_capacity = old_capacity + old_capacity / 2; if (size > new_capacity)
new_capacity = size; elseif (new_capacity > max_size)
new_capacity = max_of(size, max_size);
T* old_data = buf.data();
T* new_data = self.alloc_.allocate(new_capacity); // Suppress a bogus -Wstringop-overflow in gcc 13.1 (#3481).
detail::assume(buf.size() <= new_capacity); // The following code doesn't throw, so the raw pointer above doesn't leak.
memcpy(new_data, old_data, buf.size() * sizeof(T));
self.set(new_data, new_capacity); // deallocate must not throw according to the standard, but even if it does, // the buffer already uses the new storage and will deallocate it in // destructor. if (old_data != self.store_) self.alloc_.deallocate(old_data, old_capacity);
}
public: using value_type = T; using const_reference = const T&;
private: // Move data from other to this buffer.
FMT_CONSTEXPR20 void move(basic_memory_buffer& other) {
alloc_ = std::move(other.alloc_);
T* data = other.data();
size_t size = other.size(), capacity = other.capacity(); if (data == other.store_) { this->set(store_, capacity);
detail::copy<T>(other.store_, other.store_ + size, store_);
} else { this->set(data, capacity); // Set pointer to the inline array so that delete is not called // when deallocating.
other.set(other.store_, 0);
other.clear();
} this->resize(size);
}
public: /// Constructs a `basic_memory_buffer` object moving the content of the other /// object to it.
FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other) noexcept
: detail::buffer<T>(grow) {
move(other);
}
/// Moves the content of the other `basic_memory_buffer` object to this one. autooperator=(basic_memory_buffer&& other) noexcept -> basic_memory_buffer& {
FMT_ASSERT(this != &other, "");
deallocate();
move(other); return *this;
}
// Returns a copy of the allocator associated with this buffer. auto get_allocator() const -> Allocator { return alloc_; }
/// Resizes the buffer to contain `count` elements. If T is a POD type new /// elements may not be initialized.
FMT_CONSTEXPR void resize(size_t count) { this->try_resize(count); }
/// Increases the buffer capacity to `new_capacity`. void reserve(size_t new_capacity) { this->try_reserve(new_capacity); }
/// Formats `args` according to specifications in `fmt` and writes the /// output to the file. template <typename... T> void print(format_string<T...> fmt, T&&... args) { if (buf_)
fmt::format_to(appender(*buf_), fmt, std::forward<T>(args)...); else
fmt::print(file_, fmt, std::forward<T>(args)...);
}
};
class string_buffer { private:
std::string str_;
detail::container_buffer<std::string> buf_;
// Suppress a misleading warning in older versions of clang.
FMT_PRAGMA_CLANG(diagnostic ignored "-Wweak-vtables")
/// An error reported from a formatting function. class FMT_SO_VISIBILITY("default") format_error : public std::runtime_error { public: using std::runtime_error::runtime_error;
};
// Converts a compile-time string to basic_string_view. template <typenameChar, size_t N>
constexpr auto compile_string_to_view(constChar (&s)[N])
-> basic_string_view<Char> { // Remove trailing NUL character if needed. Won't be present if this is used // with a raw character array (i.e. not defined as a string). return {s, N - (std::char_traits<Char>::to_int_type(s[N - 1]) == 0 ? 1 : 0)};
} template <typenameChar>
constexpr auto compile_string_to_view(basic_string_view<Char> s)
-> basic_string_view<Char> { return s;
}
} // namespace detail
// A generic formatting context with custom output iterator and character // (code unit) support. Char is the format string code unit type which can be // different from OutputIt::value_type. template <typename OutputIt, typenameChar> class generic_context { private:
OutputIt out_;
basic_format_args<generic_context> args_;
detail::locale_ref loc_;
public: using char_type = Char; using iterator = OutputIt; using parse_context_type FMT_DEPRECATED = parse_context<Char>; template <typename T> using formatter_type FMT_DEPRECATED = formatter<T, Char>; enum { builtin_types = FMT_BUILTIN_TYPES };
// A locale facet that formats values in UTF-8. // It is parameterized on the locale to avoid the heavy <locale> include. template <typename Locale> class format_facet : public Locale::facet { private:
std::string separator_;
std::string grouping_;
std::string decimal_point_;
// Returns true if value is negative, false otherwise. // Same as `value < 0` but doesn't produce warnings if T is an unsigned type. template <typename T, FMT_ENABLE_IF(is_signed<T>::value)>
constexpr auto is_negative(T value) -> bool { return value < 0;
} template <typename T, FMT_ENABLE_IF(!is_signed<T>::value)>
constexpr auto is_negative(T) -> bool { returnfalse;
}
// Smallest of uint32_t, uint64_t, uint128_t that is large enough to // represent all values of an integral type T. template <typename T> using uint32_or_64_or_128_t =
conditional_t<num_bits<T>() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS,
uint32_t,
conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>; template <typename T> using uint64_or_128_t = conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>;
// Converts value in the range [0, 100) to a string. // GCC generates slightly better code when value is pointer-size. inlineauto digits2(size_t value) -> constchar* { // Align data since unaligned access may be slower when crossing a // hardware-specific boundary.
alignas(2) staticconstchar data[] = "0001020304050607080910111213141516171819" "2021222324252627282930313233343536373839" "4041424344454647484950515253545556575859" "6061626364656667686970717273747576777879" "8081828384858687888990919293949596979899"; return &data[value * 2];
}
template <typename T> FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { int count = 1; for (;;) { // Integer division is slow so do it for a group of four digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. if (n < 10) return count; if (n < 100) return count + 1; if (n < 1000) return count + 2; if (n < 10000) return count + 3;
n /= 10000u;
count += 4;
}
} #if FMT_USE_INT128
FMT_CONSTEXPR inlineauto count_digits(uint128_opt n) -> int { return count_digits_fallback(n);
} #endif
#ifdef FMT_BUILTIN_CLZLL // It is a separate function rather than a part of count_digits to workaround // the lack of static constexpr in constexpr functions. inlineauto do_count_digits(uint64_t n) -> int { // This has comparable performance to the version by Kendall Willets // (https://github.com/fmtlib/format-benchmark/blob/master/digits10) // but uses smaller tables. // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). static constexpr uint8_t bsr2log10[] = { 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; static constexpr const uint64_t zero_or_powers_of_10[] = { 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), 10000000000000000000ULL}; return t - (n < zero_or_powers_of_10[t]);
} #endif
// Returns the number of decimal digits in n. Leading zeros are not counted // except for n == 0 in which case count_digits returns 1.
FMT_CONSTEXPR20 inlineauto count_digits(uint64_t n) -> int { #ifdef FMT_BUILTIN_CLZLL if (!is_constant_evaluated() && !FMT_OPTIMIZE_SIZE) return do_count_digits(n); #endif return count_digits_fallback(n);
}
// Counts the number of digits in n. BITS = log2(radix). template <int BITS, typename UInt>
FMT_CONSTEXPR auto count_digits(UInt n) -> int { #ifdef FMT_BUILTIN_CLZ if (!is_constant_evaluated() && num_bits<UInt>() == 32) return (FMT_BUILTIN_CLZ(static_cast<uint32_t>(n) | 1) ^ 31) / BITS + 1; #endif // Lambda avoids unreachable code warnings from NVHPC. return [](UInt m) { int num_digits = 0; do {
++num_digits;
} while ((m >>= BITS) != 0); return num_digits;
}(n);
}
#ifdef FMT_BUILTIN_CLZ // It is a separate function rather than a part of count_digits to workaround // the lack of static constexpr in constexpr functions.
FMT_INLINE auto do_count_digits(uint32_t n) -> int { // An optimization by Kendall Willets from https://bit.ly/3uOIQrB. // This increments the upper 32 bits (log10(T) - 1) when >= T is added. # define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T) static constexpr uint64_t table[] = {
FMT_INC(0), FMT_INC(0), FMT_INC(0), // 8
FMT_INC(10), FMT_INC(10), FMT_INC(10), // 64
FMT_INC(100), FMT_INC(100), FMT_INC(100), // 512
FMT_INC(1000), FMT_INC(1000), FMT_INC(1000), // 4096
FMT_INC(10000), FMT_INC(10000), FMT_INC(10000), // 32k
FMT_INC(100000), FMT_INC(100000), FMT_INC(100000), // 256k
FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000), // 2048k
FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000), // 16M
FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000), // 128M
FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000), // 1024M
FMT_INC(1000000000), FMT_INC(1000000000) // 4B
}; auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31]; returnstatic_cast<int>((n + inc) >> 32);
} #endif
// Optional version of count_digits for better performance on 32-bit platforms.
FMT_CONSTEXPR20 inlineauto count_digits(uint32_t n) -> int { #ifdef FMT_BUILTIN_CLZ if (!is_constant_evaluated() && !FMT_OPTIMIZE_SIZE) return do_count_digits(n); #endif return count_digits_fallback(n);
}
template <typenameInt> constexpr auto digits10() noexcept -> int { return std::numeric_limits<Int>::digits10;
} template <> constexpr auto digits10<int128_opt>() noexcept -> int { return38; } template <> constexpr auto digits10<uint128_t>() noexcept -> int { return38; }
// Writes a two-digit value to out. template <typenameChar>
FMT_CONSTEXPR20 FMT_INLINE void write2digits(Char* out, size_t value) { if (!is_constant_evaluated() && std::is_same<Char, char>::value &&
!FMT_OPTIMIZE_SIZE) {
memcpy(out, digits2(value), 2); return;
}
*out++ = static_cast<Char>('0' + value / 10);
*out = static_cast<Char>('0' + value % 10);
}
// Formats a decimal unsigned integer value writing to out pointing to a buffer // of specified size. The caller must ensure that the buffer is large enough. template <typenameChar, typename UInt>
FMT_CONSTEXPR20 auto do_format_decimal(Char* out, UInt value, int size)
-> Char* {
FMT_ASSERT(size >= count_digits(value), "invalid digit count"); unsigned n = to_unsigned(size); while (value >= 100) { // Integer division is slow so do it for a group of two digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison.
n -= 2;
write2digits(out + n, static_cast<unsigned>(value % 100));
value /= 100;
} if (value >= 10) {
n -= 2;
write2digits(out + n, static_cast<unsigned>(value));
} else {
out[--n] = static_cast<Char>('0' + value);
} return out + n;
}
template <typenameChar, typename UInt>
FMT_CONSTEXPR FMT_INLINE auto format_decimal(Char* out, UInt value, int num_digits) -> Char* {
do_format_decimal(out, value, num_digits); return out + num_digits;
}
template <typenameChar, typename UInt, typename OutputIt,
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value)>
FMT_CONSTEXPR auto format_decimal(OutputIt out, UInt value, int num_digits)
-> OutputIt { if (auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
do_format_decimal(ptr, value, num_digits); return out;
} // Buffer is large enough to hold all digits (digits10 + 1). char buffer[digits10<UInt>() + 1]; if (is_constant_evaluated()) fill_n(buffer, sizeof(buffer), '\0');
do_format_decimal(buffer, value, num_digits); return copy_noinline<Char>(buffer, buffer + num_digits, out);
}
// Formats an unsigned integer in the power of two base (binary, octal, hex). template <typenameChar, typename UInt>
FMT_CONSTEXPR auto format_base2e(int base_bits, Char* out, UInt value, int num_digits, bool upper = false) -> Char* {
do_format_base2e(base_bits, out, value, num_digits, upper); return out + num_digits;
}
template <typenameChar, typename OutputIt, typename UInt,
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value)>
FMT_CONSTEXPR inlineauto format_base2e(int base_bits, OutputIt out, UInt value, int num_digits, bool upper = false)
-> OutputIt { if (auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
format_base2e(base_bits, ptr, value, num_digits, upper); return out;
} // Make buffer large enough for any base. char buffer[num_bits<UInt>()]; if (is_constant_evaluated()) fill_n(buffer, sizeof(buffer), '\0');
format_base2e(base_bits, buffer, value, num_digits, upper); return detail::copy_noinline<Char>(buffer, buffer + num_digits, out);
}
// A converter from UTF-8 to UTF-16. class utf8_to_utf16 { private:
basic_memory_buffer<wchar_t> buffer_;
// Performs conversion returning a bool instead of throwing exception on // conversion error. This method may still throw in case of memory allocation // error. auto convert(basic_string_view<WChar> s,
to_utf8_error_policy policy = to_utf8_error_policy::abort)
-> bool { if (!convert(buffer_, s, policy)) returnfalse;
buffer_.push_back(0); returntrue;
} staticauto convert(Buffer& buf, basic_string_view<WChar> s,
to_utf8_error_policy policy = to_utf8_error_policy::abort)
-> bool { for (auto p = s.begin(); p != s.end(); ++p) {
uint32_t c = static_cast<uint32_t>(*p); if (sizeof(WChar) == 2 && c >= 0xd800 && c <= 0xdfff) { // Handle a surrogate pair.
++p; if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) { if (policy == to_utf8_error_policy::abort) returnfalse;
buf.append(string_view("\xEF\xBF\xBD"));
--p; continue;
} else {
c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;
}
} if (c < 0x80) {
buf.push_back(static_cast<char>(c));
} elseif (c < 0x800) {
buf.push_back(static_cast<char>(0xc0 | (c >> 6)));
buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
} elseif ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
buf.push_back(static_cast<char>(0xe0 | (c >> 12)));
buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
} elseif (c >= 0x10000 && c <= 0x10ffff) {
buf.push_back(static_cast<char>(0xf0 | (c >> 18)));
buf.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
} else { returnfalse;
}
} returntrue;
}
};
// Computes 128-bit result of multiplication of two 64-bit unsigned integers. inlineauto umul128(uint64_t x, uint64_t y) noexcept -> uint128_fallback { #if FMT_USE_INT128 auto p = static_cast<uint128_opt>(x) * static_cast<uint128_opt>(y); return {static_cast<uint64_t>(p >> 64), static_cast<uint64_t>(p)}; #elifdefined(_MSC_VER) && defined(_M_X64) auto hi = uint64_t(); auto lo = _umul128(x, y, &hi); return {hi, lo}; #else const uint64_t mask = static_cast<uint64_t>(max_value<uint32_t>());
uint64_t a = x >> 32;
uint64_t b = x & mask;
uint64_t c = y >> 32;
uint64_t d = y & mask;
uint64_t ac = a * c;
uint64_t bc = b * c;
uint64_t ad = a * d;
uint64_t bd = b * d;
namespace dragonbox { // Computes floor(log10(pow(2, e))) for e in [-2620, 2620] using the method from // https://fmt.dev/papers/Dragonbox.pdf#page=28, section 6.1. inlineauto floor_log10_pow2(int e) noexcept -> int {
FMT_ASSERT(e <= 2620 && e >= -2620, "too large exponent");
static_assert((-1 >> 1) == -1, "right shift is not arithmetic"); return (e * 315653) >> 20;
}
inlineauto floor_log2_pow10(int e) noexcept -> int {
FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent"); return (e * 1741647) >> 19;
}
// Computes upper 64 bits of multiplication of two 64-bit unsigned integers. inlineauto umul128_upper64(uint64_t x, uint64_t y) noexcept -> uint64_t { #if FMT_USE_INT128 auto p = static_cast<uint128_opt>(x) * static_cast<uint128_opt>(y); returnstatic_cast<uint64_t>(p >> 64); #elifdefined(_MSC_VER) && defined(_M_X64) return __umulh(x, y); #else return umul128(x, y).high(); #endif
}
// Computes upper 128 bits of multiplication of a 64-bit unsigned integer and a // 128-bit unsigned integer. inlineauto umul192_upper128(uint64_t x, uint128_fallback y) noexcept
-> uint128_fallback {
uint128_fallback r = umul128(x, y.high());
r += umul128_upper64(x, y.low()); return r;
}
FMT_API auto get_cached_power(int k) noexcept -> uint128_fallback;
// Type-specific information that Dragonbox uses. template <typename T, typename Enable = void> struct float_info;
// Returns true iff Float has the implicit bit which is not stored. template <typenameFloat> constexpr auto has_implicit_bit() -> bool { // An 80-bit FP number has a 64-bit significand an no implicit bit. return std::numeric_limits<Float>::digits != 64;
}
// Returns the number of significand bits stored in Float. The implicit bit is // not counted since it is not stored. template <typenameFloat> constexpr auto num_significand_bits() -> int { // std::numeric_limits may not support __float128. return is_float128<Float>() ? 112
: (std::numeric_limits<Float>::digits -
(has_implicit_bit<Float>() ? 1 : 0));
}
template <typenameFloat>
constexpr auto exponent_mask() -> typename dragonbox::float_info<Float>::carrier_uint { using float_uint = typename dragonbox::float_info<Float>::carrier_uint; return ((float_uint(1) << dragonbox::float_info<Float>::exponent_bits) - 1)
<< num_significand_bits<Float>();
} template <typenameFloat> constexpr auto exponent_bias() -> int { // std::numeric_limits may not support __float128. return is_float128<Float>() ? 16383
: std::numeric_limits<Float>::max_exponent - 1;
}
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer. template <typenameChar, typename OutputIt>
FMT_CONSTEXPR auto write_exponent(int exp, OutputIt out) -> OutputIt {
FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range"); if (exp < 0) {
*out++ = static_cast<Char>('-');
exp = -exp;
} else {
*out++ = static_cast<Char>('+');
} auto uexp = static_cast<uint32_t>(exp); if (is_constant_evaluated()) { if (uexp < 10) *out++ = '0'; return format_decimal<Char>(out, uexp, count_digits(uexp));
} if (uexp >= 100u) { constchar* top = digits2(uexp / 100); if (uexp >= 1000u) *out++ = static_cast<Char>(top[0]);
*out++ = static_cast<Char>(top[1]);
uexp %= 100;
} constchar* d = digits2(uexp);
*out++ = static_cast<Char>(d[0]);
*out++ = static_cast<Char>(d[1]); return out;
}
// A floating-point number f * pow(2, e) where F is an unsigned type. template <typename F> struct basic_fp {
F f; int e;
// Constructs fp from an IEEE754 floating-point number. template <typenameFloat> FMT_CONSTEXPR basic_fp(Float n) { assign(n); }
// Assigns n to this and return true iff predecessor is closer than successor. template <typenameFloat, FMT_ENABLE_IF(!is_double_double<Float>::value)>
FMT_CONSTEXPR auto assign(Float n) -> bool {
static_assert(std::numeric_limits<Float>::digits <= 113, "unsupported FP"); // Assume Float is in the format [sign][exponent][significand]. using carrier_uint = typename dragonbox::float_info<Float>::carrier_uint; constauto num_float_significand_bits =
detail::num_significand_bits<Float>(); constauto implicit_bit = carrier_uint(1) << num_float_significand_bits; constauto significand_mask = implicit_bit - 1; auto u = bit_cast<carrier_uint>(n);
f = static_cast<F>(u & significand_mask); auto biased_e = static_cast<int>((u & exponent_mask<Float>()) >>
num_float_significand_bits); // The predecessor is closer if n is a normalized power of 2 (f == 0) // other than the smallest normalized number (biased_e > 1). auto is_predecessor_closer = f == 0 && biased_e > 1; if (biased_e == 0)
biased_e = 1; // Subnormals use biased exponent 1 (min exponent). elseif (has_implicit_bit<Float>())
f += static_cast<F>(implicit_bit);
e = biased_e - exponent_bias<Float>() - num_float_significand_bits; if (!has_implicit_bit<Float>()) ++e; return is_predecessor_closer;
}
template <typenameChar, typename OutputIt>
FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, const basic_specs& specs) -> OutputIt { auto fill_size = specs.fill_size(); if (fill_size == 1) return detail::fill_n(it, n, specs.fill_unit<Char>()); if (constChar* data = specs.fill<Char>()) { for (size_t i = 0; i < n; ++i) it = copy<Char>(data, data + fill_size, it);
} return it;
}
// Writes the output of f, padded according to format specifications in specs. // size: output size in code units. // width: output display width in (terminal) column positions. template <typenameChar, align default_align = align::left, typename OutputIt, typename F>
FMT_CONSTEXPR auto write_padded(OutputIt out, const format_specs& specs,
size_t size, size_t width, F&& f) -> OutputIt {
static_assert(default_align == align::left || default_align == align::right, ""); unsigned spec_width = to_unsigned(specs.width);
size_t padding = spec_width > width ? spec_width - width : 0; // Shifts are encoded as string literals because static constexpr is not // supported in constexpr functions. auto* shifts =
default_align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01";
size_t left_padding = padding >> shifts[static_cast<int>(specs.align())];
size_t right_padding = padding - left_padding; auto it = reserve(out, size + padding * specs.fill_size()); if (left_padding != 0) it = fill<Char>(it, left_padding, specs);
it = f(it); if (right_padding != 0) it = fill<Char>(it, right_padding, specs); return base_iterator(out, it);
}
auto has_separator() const -> bool { return !thousands_sep_.empty(); }
auto count_separators(int num_digits) const -> int { int count = 0; auto state = initial_state(); while (num_digits > next(state)) ++count; return count;
}
// Applies grouping to digits and write the output to out. template <typename Out, typename C> auto apply(Out out, basic_string_view<C> digits) const -> Out { auto num_digits = static_cast<int>(digits.size()); auto separators = basic_memory_buffer<int>();
separators.push_back(0); auto state = initial_state(); while (int i = next(state)) { if (i >= num_digits) break;
separators.push_back(i);
} for (int i = 0, sep_index = static_cast<int>(separators.size() - 1);
i < num_digits; ++i) { if (num_digits - i == separators[sep_index]) {
out = copy<Char>(thousands_sep_.data(),
thousands_sep_.data() + thousands_sep_.size(), out);
--sep_index;
}
*out++ = static_cast<Char>(digits[to_unsigned(i)]);
} return out;
}
};
constexpr int buffer_size = num_bits<T>(); char buffer[buffer_size]; if (is_constant_evaluated()) fill_n(buffer, buffer_size, '\0'); constchar* begin = nullptr; constchar* end = buffer + buffer_size;
auto abs_value = arg.abs_value; auto prefix = arg.prefix; switch (specs.type()) { default: FMT_ASSERT(false, ""); FMT_FALLTHROUGH; case presentation_type::none: case presentation_type::dec:
begin = do_format_decimal(buffer, abs_value, buffer_size); break; case presentation_type::hex:
begin = do_format_base2e(4, buffer, abs_value, buffer_size, specs.upper()); if (specs.alt())
prefix_append(prefix, unsigned(specs.upper() ? 'X' : 'x') << 8 | '0'); break; case presentation_type::oct: {
begin = do_format_base2e(3, buffer, abs_value, buffer_size); // Octal prefix '0' is counted as a digit, so only add it if precision // is not greater than the number of digits. auto num_digits = end - begin; if (specs.alt() && specs.precision <= num_digits && abs_value != 0)
prefix_append(prefix, '0'); break;
} case presentation_type::bin:
begin = do_format_base2e(1, buffer, abs_value, buffer_size); if (specs.alt())
prefix_append(prefix, unsigned(specs.upper() ? 'B' : 'b') << 8 | '0'); break; case presentation_type::chr: return write_char<Char>(out, static_cast<Char>(abs_value), specs);
}
// Write an integer in the format // <left-padding><prefix><numeric-padding><digits><right-padding> // prefix contains chars in three lower bytes and the size in the fourth byte. int num_digits = static_cast<int>(end - begin); // Slightly faster check for specs.width == 0 && specs.precision == -1. if ((specs.width | (specs.precision + 1)) == 0) { auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24)); for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
*it++ = static_cast<Char>(p & 0xff); return base_iterator(out, copy<Char>(begin, end, it));
} auto sp = size_padding(num_digits, prefix, specs); unsigned padding = sp.padding; return write_padded<Char, align::right>(
out, specs, sp.size, [=](reserve_iterator<OutputIt> it) { for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
*it++ = static_cast<Char>(p & 0xff);
it = detail::fill_n(it, padding, static_cast<Char>('0')); return copy<Char>(begin, end, it);
});
}
inline FMT_CONSTEXPR20 void adjust_precision(int& precision, int exp10) { // Adjust fixed precision by exponent because it is relative to decimal // point. if (exp10 > 0 && precision > max_value<int>() - exp10)
FMT_THROW(format_error("number is too big"));
precision += exp10;
}
class bigint { private: // A bigint is a number in the form bigit_[N - 1] ... bigit_[0] * 32^exp_. using bigit = uint32_t; // A big digit. using double_bigit = uint64_t; enum { bigit_bits = num_bits<bigit>() }; enum { bigits_capacity = 32 };
basic_memory_buffer<bigit, bigits_capacity> bigits_; int exp_;
friendstruct formatter<bigint>;
FMT_CONSTEXPR auto get_bigit(int i) const -> bigit { return i >= exp_ && i < num_bigits() ? bigits_[i - exp_] : 0;
}
FMT_CONSTEXPR void subtract_bigits(int index, bigit other, bigit& borrow) { auto result = double_bigit(bigits_[index]) - other - borrow;
bigits_[index] = static_cast<bigit>(result);
borrow = static_cast<bigit>(result >> (bigit_bits * 2 - 1));
}
friend FMT_CONSTEXPR auto compare(const bigint& b1, const bigint& b2) -> int { int num_bigits1 = b1.num_bigits(), num_bigits2 = b2.num_bigits(); if (num_bigits1 != num_bigits2) return num_bigits1 > num_bigits2 ? 1 : -1; int i = static_cast<int>(b1.bigits_.size()) - 1; int j = static_cast<int>(b2.bigits_.size()) - 1; int end = i - j; if (end < 0) end = 0; for (; i >= end; --i, --j) {
bigit b1_bigit = b1.bigits_[i], b2_bigit = b2.bigits_[j]; if (b1_bigit != b2_bigit) return b1_bigit > b2_bigit ? 1 : -1;
} if (i != j) return i > j ? 1 : -1; return0;
}
// Returns compare(lhs1 + lhs2, rhs). friend FMT_CONSTEXPR auto add_compare(const bigint& lhs1, const bigint& lhs2, const bigint& rhs) -> int { int max_lhs_bigits = max_of(lhs1.num_bigits(), lhs2.num_bigits()); int num_rhs_bigits = rhs.num_bigits(); if (max_lhs_bigits + 1 < num_rhs_bigits) return -1; if (max_lhs_bigits > num_rhs_bigits) return1;
double_bigit borrow = 0; int min_exp = min_of(min_of(lhs1.exp_, lhs2.exp_), rhs.exp_); for (int i = num_rhs_bigits - 1; i >= min_exp; --i) {
double_bigit sum = double_bigit(lhs1.get_bigit(i)) + lhs2.get_bigit(i);
bigit rhs_bigit = rhs.get_bigit(i); if (sum > rhs_bigit + borrow) return1;
borrow = rhs_bigit + borrow - sum; if (borrow > 1) return -1;
borrow <<= bigit_bits;
} return borrow != 0 ? -1 : 0;
}
// Assigns pow(10, exp) to this bigint.
FMT_CONSTEXPR20 void assign_pow10(int exp) {
FMT_ASSERT(exp >= 0, ""); if (exp == 0) return *this = 1; int bitmask = 1 << (num_bits<unsigned>() -
countl_zero(static_cast<uint32_t>(exp)) - 1); // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by // repeated squaring and multiplication.
*this = 5;
bitmask >>= 1; while (bitmask != 0) {
square(); if ((exp & bitmask) != 0) *this *= 5;
bitmask >>= 1;
}
*this <<= exp; // Multiply by pow(2, exp) by shifting.
}
FMT_CONSTEXPR20 void square() { int num_bigits = static_cast<int>(bigits_.size()); int num_result_bigits = 2 * num_bigits;
basic_memory_buffer<bigit, bigits_capacity> n(std::move(bigits_));
bigits_.resize(to_unsigned(num_result_bigits)); auto sum = uint128_t(); for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) { // Compute bigit at position bigit_index of the result by adding // cross-product terms n[i] * n[j] such that i + j == bigit_index. for (int i = 0, j = bigit_index; j >= 0; ++i, --j) { // Most terms are multiplied twice which can be optimized in the future.
sum += double_bigit(n[i]) * n[j];
}
bigits_[bigit_index] = static_cast<bigit>(sum);
sum >>= num_bits<bigit>(); // Compute the carry.
} // Do the same for the top half. for (int bigit_index = num_bigits; bigit_index < num_result_bigits;
++bigit_index) { for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;)
sum += double_bigit(n[i++]) * n[j--];
bigits_[bigit_index] = static_cast<bigit>(sum);
sum >>= num_bits<bigit>();
}
remove_leading_zeros();
exp_ *= 2;
}
// If this bigint has a bigger exponent than other, adds trailing zero to make // exponents equal. This simplifies some operations such as subtraction.
FMT_CONSTEXPR void align(const bigint& other) { int exp_difference = exp_ - other.exp_; if (exp_difference <= 0) return; int num_bigits = static_cast<int>(bigits_.size());
bigits_.resize(to_unsigned(num_bigits + exp_difference)); for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j)
bigits_[j] = bigits_[i];
memset(bigits_.data(), 0, to_unsigned(exp_difference) * sizeof(bigit));
exp_ -= exp_difference;
}
// Divides this bignum by divisor, assigning the remainder to this and // returning the quotient.
FMT_CONSTEXPR auto divmod_assign(const bigint& divisor) -> int {
FMT_ASSERT(this != &divisor, ""); if (compare(*this, divisor) < 0) return0;
FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, "");
align(divisor); int quotient = 0; do {
subtract_aligned(divisor);
++quotient;
} while (compare(*this, divisor) >= 0); return quotient;
}
};
// format_dragon flags. enum dragon {
predecessor_closer = 1,
fixup = 2, // Run fixup to correct exp10 which can be off by one.
fixed = 4,
};
// Formats a floating-point number using a variation of the Fixed-Precision // Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White: // https://fmt.dev/papers/p372-steele.pdf.
FMT_CONSTEXPR20 inlinevoid format_dragon(basic_fp<uint128_t> value, unsigned flags, int num_digits,
buffer<char>& buf, int& exp10) {
bigint numerator; // 2 * R in (FPP)^2.
bigint denominator; // 2 * S in (FPP)^2. // lower and upper are differences between value and corresponding boundaries.
bigint lower; // (M^- in (FPP)^2).
bigint upper_store; // upper's value if different from lower.
bigint* upper = nullptr; // (M^+ in (FPP)^2). // Shift numerator and denominator by an extra bit or two (if lower boundary // is closer) to make lower and upper integers. This eliminates multiplication // by 2 during later computations. bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0; int shift = is_predecessor_closer ? 2 : 1; if (value.e >= 0) {
numerator = value.f;
numerator <<= value.e + shift;
lower = 1;
lower <<= value.e; if (is_predecessor_closer) {
upper_store = 1;
upper_store <<= value.e + 1;
upper = &upper_store;
}
denominator.assign_pow10(exp10);
denominator <<= shift;
} elseif (exp10 < 0) {
numerator.assign_pow10(-exp10);
lower.assign(numerator); if (is_predecessor_closer) {
upper_store.assign(numerator);
upper_store <<= 1;
upper = &upper_store;
}
numerator *= value.f;
numerator <<= shift;
denominator = 1;
denominator <<= shift - value.e;
} else {
numerator = value.f;
numerator <<= shift;
denominator.assign_pow10(exp10);
denominator <<= shift - value.e;
lower = 1; if (is_predecessor_closer) {
upper_store = 1ULL << 1;
upper = &upper_store;
}
} int even = static_cast<int>((value.f & 1) == 0); if (!upper) upper = &lower; bool shortest = num_digits < 0; if ((flags & dragon::fixup) != 0) { if (add_compare(numerator, *upper, denominator) + even <= 0) {
--exp10;
numerator *= 10; if (num_digits < 0) {
lower *= 10; if (upper != &lower) *upper *= 10;
}
} if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1);
} // Invariant: value == (numerator / denominator) * pow(10, exp10). if (shortest) { // Generate the shortest representation.
num_digits = 0; char* data = buf.data(); for (;;) { int digit = numerator.divmod_assign(denominator); bool low = compare(numerator, lower) - even < 0; // numerator <[=] lower. // numerator + upper >[=] pow10: bool high = add_compare(numerator, *upper, denominator) + even > 0;
data[num_digits++] = static_cast<char>('0' + digit); if (low || high) { if (!low) {
++data[num_digits - 1];
} elseif (high) { int result = add_compare(numerator, numerator, denominator); // Round half to even. if (result > 0 || (result == 0 && (digit % 2) != 0))
++data[num_digits - 1];
}
buf.try_resize(to_unsigned(num_digits));
exp10 -= num_digits - 1; return;
}
numerator *= 10;
lower *= 10; if (upper != &lower) *upper *= 10;
}
} // Generate the given number of digits.
exp10 -= num_digits - 1; if (num_digits <= 0) { auto digit = '0'; if (num_digits == 0) {
denominator *= 10;
digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0';
}
buf.push_back(digit); return;
}
buf.try_resize(to_unsigned(num_digits)); for (int i = 0; i < num_digits - 1; ++i) { int digit = numerator.divmod_assign(denominator);
buf[i] = static_cast<char>('0' + digit);
numerator *= 10;
} int digit = numerator.divmod_assign(denominator); auto result = add_compare(numerator, numerator, denominator); if (result > 0 || (result == 0 && (digit % 2) != 0)) { if (digit == 9) { constauto overflow = '0' + 10;
buf[num_digits - 1] = overflow; // Propagate the carry. for (int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) {
buf[i] = '0';
++buf[i - 1];
} if (buf[0] == overflow) {
buf[0] = '1'; if ((flags & dragon::fixed) != 0)
buf.push_back('0'); else
++exp10;
} return;
}
++digit;
}
buf[num_digits - 1] = static_cast<char>('0' + digit);
}
// Formats a floating-point number using the hexfloat format. template <typenameFloat, FMT_ENABLE_IF(!is_double_double<Float>::value)>
FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs,
buffer<char>& buf) { // float is passed as double to reduce the number of instantiations and to // simplify implementation.
static_assert(!std::is_same<Float, float>::value, "");
using info = dragonbox::float_info<Float>;
// Assume Float is in the format [sign][exponent][significand]. using carrier_uint = typename info::carrier_uint;
constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { // For checking rounding thresholds. // The kth entry is chosen to be the smallest integer such that the // upper 32-bits of 10^(k+1) times it is strictly bigger than 5 * 10^k. // It is equal to ceil(2^31 + 2^32/10^(k + 1)). // These are stored in a string literal because we cannot have static arrays // in constexpr functions and non-static ones are poorly optimized. return U"\x9999999a\x828f5c29\x80418938\x80068db9\x8000a7c6\x800010c7"
U"\x800001ae\x8000002b"[index];
}
template <typenameFloat>
FMT_CONSTEXPR20 auto format_float(Float value, int precision, const format_specs& specs, bool binary32,
buffer<char>& buf) -> int { // GCC and old clang seem to hit this even though this function isn't called. #ifdef __clang__ #if __clang_major__ >= 17
static_assert(false, "This method is not to be used in Gecko, use format_float_gecko"); #endif #endif // float is passed as double to reduce the number of instantiations.
static_assert(!std::is_same<Float, float>::value, ""); auto converted_value = convert_float(value);
int exp = 0; bool use_dragon = true; unsigned dragon_flags = 0; if (!is_fast_float<Float>() || is_constant_evaluated()) { constauto inv_log2_10 = 0.3010299956639812; // 1 / log2(10) using info = dragonbox::float_info<decltype(converted_value)>; constauto f = basic_fp<typename info::carrier_uint>(converted_value); // Compute exp, an approximate power of 10, such that // 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1). // This is based on log10(value) == log2(value) / log2(10) and approximation // of log2(value) by e + num_fraction_bits idea from double-conversion. auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10;
exp = static_cast<int>(e); if (e > exp) ++exp; // Compute ceil.
dragon_flags = dragon::fixup;
} else { // Extract significand bits and exponent bits. using info = dragonbox::float_info<double>; auto br = bit_cast<uint64_t>(static_cast<double>(value));
// Compute the first several nonzero decimal significand digits. // We call the number we get the first segment. constint k = info::kappa - dragonbox::floor_log10_pow2(exponent);
exp = -k; constint beta = exponent + dragonbox::floor_log2_pow10(k);
uint64_t first_segment; bool has_more_segments; int digits_in_the_first_segment;
{ constauto r = dragonbox::umul192_upper128(
significand << beta, dragonbox::get_cached_power(k));
first_segment = r.high();
has_more_segments = r.low() != 0;
// The first segment can have 18 ~ 19 digits. if (first_segment >= 1000000000000000000ULL) {
digits_in_the_first_segment = 19;
} else { // When it is of 18-digits, we align it to 19-digits by adding a bogus // zero at the end.
digits_in_the_first_segment = 18;
first_segment *= 10;
}
}
// Compute the actual number of decimal digits to print. if (fixed) adjust_precision(precision, exp + digits_in_the_first_segment);
// Use Dragon4 only when there might be not enough digits in the first // segment. if (digits_in_the_first_segment > precision) {
use_dragon = false;
if (precision <= 0) {
exp += digits_in_the_first_segment;
if (precision < 0) { // Nothing to do, since all we have are just leading zeros.
buf.try_resize(0);
} else { // We may need to round-up.
buf.try_resize(1); if ((first_segment | static_cast<uint64_t>(has_more_segments)) > 5000000000000000000ULL) {
buf[0] = '1';
} else {
buf[0] = '0';
}
}
} // precision <= 0 else {
exp += digits_in_the_first_segment - precision;
// When precision > 0, we divide the first segment into three // subsegments, each with 9, 9, and 0 ~ 1 digits so that each fits // in 32-bits which usually allows faster calculation than in // 64-bits. Since some compiler (e.g. MSVC) doesn't know how to optimize // division-by-constant for large 64-bit divisors, we do it here // manually. The magic number 7922816251426433760 below is equal to // ceil(2^(64+32) / 10^10). const uint32_t first_subsegment = static_cast<uint32_t>(
dragonbox::umul128_upper64(first_segment, 7922816251426433760ULL) >> 32); const uint64_t second_third_subsegments =
first_segment - first_subsegment * 10000000000ULL;
// Print a 9-digits subsegment, either the first or the second. auto print_subsegment = [&](uint32_t subsegment, char* buffer) { int number_of_digits_printed = 0;
// If we want to print an odd number of digits from the subsegment, if ((number_of_digits_to_print & 1) != 0) { // Convert to 64-bit fixed-point fractional form with 1-digit // integer part. The magic number 720575941 is a good enough // approximation of 2^(32 + 24) / 10^8; see // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case // for details.
prod = ((subsegment * static_cast<uint64_t>(720575941)) >> 24) + 1;
digits = static_cast<uint32_t>(prod >> 32);
*buffer = static_cast<char>('0' + digits);
number_of_digits_printed++;
} // If we want to print an even number of digits from the // first_subsegment, else { // Convert to 64-bit fixed-point fractional form with 2-digits // integer part. The magic number 450359963 is a good enough // approximation of 2^(32 + 20) / 10^7; see // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case // for details.
prod = ((subsegment * static_cast<uint64_t>(450359963)) >> 20) + 1;
digits = static_cast<uint32_t>(prod >> 32);
write2digits(buffer, digits);
number_of_digits_printed += 2;
}
// Print first subsegment.
print_subsegment(first_subsegment, buf.data());
// Perform rounding if the first subsegment is the last subsegment to // print. if (precision <= 9) { // Rounding inside the subsegment. // We round-up if: // - either the fractional part is strictly larger than 1/2, or // - the fractional part is exactly 1/2 and the last digit is odd. // We rely on the following observations: // - If fractional_part >= threshold, then the fractional part is // strictly larger than 1/2. // - If the MSB of fractional_part is set, then the fractional part // must be at least 1/2. // - When the MSB of fractional_part is set, either // second_third_subsegments being nonzero or has_more_segments // being true means there are further digits not printed, so the // fractional part is strictly larger than 1/2. if (precision < 9) {
uint32_t fractional_part = static_cast<uint32_t>(prod);
should_round_up =
fractional_part >= fractional_part_rounding_thresholds( 8 - number_of_digits_to_print) ||
((fractional_part >> 31) &
((digits & 1) | (second_third_subsegments != 0) |
has_more_segments)) != 0;
} // Rounding at the subsegment boundary. // In this case, the fractional part is at least 1/2 if and only if // second_third_subsegments >= 5000000000ULL, and is strictly larger // than 1/2 if we further have either second_third_subsegments > // 5000000000ULL or has_more_segments == true. else {
should_round_up = second_third_subsegments > 5000000000ULL ||
(second_third_subsegments == 5000000000ULL &&
((digits & 1) != 0 || has_more_segments));
}
} // Otherwise, print the second subsegment. else { // Compilers are not aware of how to leverage the maximum value of // second_third_subsegments to find out a better magic number which // allows us to eliminate an additional shift. 1844674407370955162 = // ceil(2^64/10) < ceil(2^64*(10^9/(10^10 - 1))). const uint32_t second_subsegment = static_cast<uint32_t>(dragonbox::umul128_upper64(
second_third_subsegments, 1844674407370955162ULL)); const uint32_t third_subsegment = static_cast<uint32_t>(second_third_subsegments) -
second_subsegment * 10;
// Rounding inside the subsegment. if (precision < 18) { // The condition third_subsegment != 0 implies that the segment was // of 19 digits, so in this case the third segment should be // consisting of a genuine digit from the input.
uint32_t fractional_part = static_cast<uint32_t>(prod);
should_round_up =
fractional_part >= fractional_part_rounding_thresholds( 8 - number_of_digits_to_print) ||
((fractional_part >> 31) &
((digits & 1) | (third_subsegment != 0) |
has_more_segments)) != 0;
} // Rounding at the subsegment boundary. else { // In this case, the segment must be of 19 digits, thus // the third subsegment should be consisting of a genuine digit from // the input.
should_round_up = third_subsegment > 5 ||
(third_subsegment == 5 &&
((digits & 1) != 0 || has_more_segments));
}
}
// Round-up if necessary. if (should_round_up) {
++buf[precision - 1]; for (int i = precision - 1; i > 0 && buf[i] > '9'; --i) {
buf[i] = '0';
++buf[i - 1];
} if (buf[0] > '9') {
buf[0] = '1'; if (fixed)
buf[precision++] = '0'; else
++exp;
}
}
buf.try_resize(to_unsigned(precision));
}
} // if (digits_in_the_first_segment > precision) else { // Adjust the exponent for its use in Dragon4.
exp += digits_in_the_first_segment - 1;
}
} if (use_dragon) { auto f = basic_fp<uint128_t>(); bool is_predecessor_closer = binary32 ? f.assign(static_cast<float>(value))
: f.assign(converted_value); if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer; if (fixed) dragon_flags |= dragon::fixed; // Limit precision to the maximum possible number of significant digits in // an IEEE754 double because we don't need to generate zeros. constint max_double_digits = 767; if (precision > max_double_digits) precision = max_double_digits;
format_dragon(f, dragon_flags, precision, buf, exp);
} if (!fixed && !specs.alt()) { // Remove trailing zeros. auto num_digits = buf.size(); while (num_digits > 0 && buf[num_digits - 1] == '0') {
--num_digits;
++exp;
}
buf.try_resize(num_digits);
} return exp;
}
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1717448#c2 for the reason // we're doing this. This copied from and should be kept in sync with // PrintfTarget::cvt_f in Gecko's mozglue/misc/Printf.cpp. template <typenameFloat> auto format_float_gecko(Float value, int precision, format_specs specs,
buffer<char>& buf) -> int {
FMT_ASSERT(detail::isfinite(value), "Non-finite values are to be handled ahead of calling this"); using double_conversion::DoubleToStringConverter; using DTSC = DoubleToStringConverter; // Printf.cpp seem to use UNIQUE_ZERO here, but then adds its own `-` further // in the code. char e = specs.upper() ? 'E' : 'e';
DTSC converter(DTSC::NO_TRAILING_ZERO |
DTSC::EMIT_POSITIVE_EXPONENT_SIGN, "inf", "nan", e, 0, 0, 4, 0, 2);
buf.try_resize(64);
double_conversion::StringBuilder builder(buf.data(), buf.size()); // Negative precision defaults to 6. if (precision == -1) { precision = 6; } bool success = false; if (specs.type() == presentation_type::exp) {
success = converter.ToExponential(value, precision, &builder);
} elseif (specs.type() == presentation_type::fixed) {
success = converter.ToFixed(value, precision, &builder);
} elseif (specs.type() == presentation_type::general ||
specs.type() == presentation_type::none) { // "If an explicit precision is zero, it shall be taken as 1."
success = converter.ToPrecision(value, precision ? precision : 1, &builder);
} else {
FMT_ASSERT(false, "Unhandled");
}
FMT_ASSERT(success, "");
buf.try_resize(builder.position()); return builder.position();
}
template <typenameChar, typename OutputIt, typename T>
FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
locale_ref loc) -> OutputIt { // Use signbit because value < 0 is false for NaN.
sign s = detail::signbit(value) ? sign::minus : specs.sign();
if (!detail::isfinite(value)) return write_nonfinite<Char>(out, detail::isnan(value), specs, s);
if (specs.align() == align::numeric && s != sign::none) {
*out++ = detail::getsign<Char>(s);
s = sign::none; if (specs.width != 0) --specs.width;
}
int precision = specs.precision;
memory_buffer buffer; if (specs.type() == presentation_type::hexfloat) { if (s != sign::none) buffer.push_back(detail::getsign<char>(s));
format_hexfloat(convert_float(value), specs, buffer); return write_bytes<Char, align::right>(out, {buffer.data(), buffer.size()},
specs);
}
specs.precision = precision;
value = abs(value);
format_float_gecko(convert_float(value), precision, specs, buffer);
size_t size = buffer.size(); if (s != sign::none) { // Space for the sign, this influences the padding calculations below.
size++; // If padding with zeros, the sign goes here, e.g. -0004.3 if (*specs.fill<Char>() == '0') {
*out++ = detail::getsign<Char>(s);
}
} return write_padded<Char, align::right>(
out, specs, size, size, [s, &buffer, specs](reserve_iterator<OutputIt> it) { // If padding with something other than zeros, the sign goes here, e.g. // ' -4.3' (quotes added for clarity). if (s != sign::none) { if (*specs.fill<Char>() != '0') {
*it++ = detail::getsign<Char>(s);
}
} constchar* data = buffer.data(); return copy<Char>(data, data + buffer.size(), it);
});
}
template <typenameChar, typename OutputIt, typename T,
FMT_ENABLE_IF(is_floating_point<T>::value)>
FMT_CONSTEXPR20 auto write(OutputIt out, T value, format_specs specs,
locale_ref loc = {}) -> OutputIt { return specs.localized() && write_loc(out, value, specs, loc)
? out
: write_float<Char>(out, value, specs, loc);
}
template <typenameChar, typename OutputIt, typename T,
FMT_ENABLE_IF(is_fast_float<T>::value)>
FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { if (is_constant_evaluated()) return write<Char>(out, value, format_specs());
auto s = detail::signbit(value) ? sign::minus : sign::none;
constexpr auto specs = format_specs(); using floaty = conditional_t<sizeof(T) >= sizeof(double), double, float>; using floaty_uint = typename dragonbox::float_info<floaty>::carrier_uint;
floaty_uint mask = exponent_mask<floaty>(); if ((bit_cast<floaty_uint>(value) & mask) == mask) return write_nonfinite<Char>(out, std::isnan(value), specs, s);
template <typenameChar, typename OutputIt, typename T,
FMT_ENABLE_IF(mapped_type_constant<T, Char>::value ==
type::custom_type &&
!std::is_fundamental<T>::value)>
FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> OutputIt { auto f = formatter<T, Char>(); auto parse_ctx = parse_context<Char>({});
f.parse(parse_ctx); auto ctx = basic_format_context<OutputIt, Char>(out, {}, {}); return f.format(value, ctx);
}
template <typename T> using is_builtin =
bool_constant<std::is_same<T, int>::value || FMT_BUILTIN_TYPES>;
// An argument visitor that formats the argument and writes it via the output // iterator. It's a class and not a generic lambda for compatibility with C++11. template <typenameChar> struct default_arg_formatter { using context = buffered_context<Char>;
basic_appender<Char> out;
voidoperator()(monostate) { report_error("argument not found"); }
voidoperator()(typename basic_format_arg<context>::handle h) { // Use a null locale since the default format must be unlocalized. auto parse_ctx = parse_context<Char>({}); auto format_ctx = context(out, {}, {});
h.format(parse_ctx, format_ctx);
}
};
voidoperator()(typename basic_format_arg<buffered_context<Char>>::handle) { // User-defined types are handled separately because they require access // to the parse context.
}
};
FMT_CONSTEXPR auto on_arg_id() -> int { return parse_ctx.next_arg_id(); }
FMT_CONSTEXPR auto on_arg_id(int id) -> int {
parse_ctx.check_arg_id(id); return id;
}
FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
parse_ctx.check_arg_id(id); int arg_id = ctx.arg_id(id); if (arg_id < 0) report_error("argument not found"); return arg_id;
}
auto on_format_specs(int id, constChar* begin, constChar* end)
-> constChar* { auto arg = get_arg(ctx, id); // Not using a visitor for custom types gives better codegen. if (arg.format_custom(begin, parse_ctx, ctx)) return parse_ctx.begin();
auto specs = dynamic_format_specs<Char>();
begin = parse_format_specs(begin, end, specs, parse_ctx, arg.type()); if (specs.dynamic()) {
handle_dynamic_spec(specs.dynamic_width(), specs.width, specs.width_ref,
ctx);
handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
specs.precision_ref, ctx);
}
/// A fast integer formatter. class format_int { private: // Buffer should be large enough to hold all digits (digits10 + 1), // a sign and a null character. enum { buffer_size = std::numeric_limits<unsignedlonglong>::digits10 + 3 }; mutablechar buffer_[buffer_size]; char* str_;
template <typename UInt>
FMT_CONSTEXPR20 auto format_unsigned(UInt value) -> char* { auto n = static_cast<detail::uint32_or_64_or_128_t<UInt>>(value); return detail::do_format_decimal(buffer_, n, buffer_size - 1);
}
template <typenameInt>
FMT_CONSTEXPR20 auto format_signed(Int value) -> char* { auto abs_value = static_cast<detail::uint32_or_64_or_128_t<Int>>(value); bool negative = value < 0; if (negative) abs_value = 0 - abs_value; auto begin = format_unsigned(abs_value); if (negative) *--begin = '-'; return begin;
}
/// Returns the number of characters written to the output buffer.
FMT_CONSTEXPR20 auto size() const -> size_t { return detail::to_unsigned(buffer_ - str_ + buffer_size - 1);
}
/// Returns a pointer to the output buffer content. No terminating null /// character is appended.
FMT_CONSTEXPR20 auto data() const -> constchar* { return str_; }
/// Returns a pointer to the output buffer content with terminating null /// character appended.
FMT_CONSTEXPR20 auto c_str() const -> constchar* {
buffer_[buffer_size - 1] = '\0'; return str_;
}
/// Returns the content of the output buffer as an `std::string`. inlineauto str() const -> std::string { return {str_, size()}; }
};
#define FMT_STRING_IMPL(s, base) \
[] { \ /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ /* Use a macro-like name to avoid shadowing warnings. */ \ struct FMT_VISIBILITY("hidden") FMT_COMPILE_STRING : base { \ using char_type = fmt::remove_cvref_t<decltype(s[0])>; \
FMT_CONSTEXPR explicitoperator fmt::basic_string_view<char_type>() \ const { \ return fmt::detail::compile_string_to_view<char_type>(s); \
} \
}; \ using FMT_STRING_VIEW = \
fmt::basic_string_view<typename FMT_COMPILE_STRING::char_type>; \
fmt::detail::ignore_unused(FMT_STRING_VIEW(FMT_COMPILE_STRING())); \ return FMT_COMPILE_STRING(); \
}()
/** *Constructsacompile-timeformatstringfromastringliteral`s`. * ***Example**: * *// A compile-time error because 'd' is an invalid specifier for strings. *std::strings=fmt::format(FMT_STRING("{:d}"),"foo");
*/ #define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string)
// Reports a system error without throwing an exception. // Can be used to report errors from destructors.
FMT_API void report_system_error(int error_code, constchar* message) noexcept;
/** *Converts`value`to`std::string`usingthedefaultformatfortype`T`. * ***Example**: * *std::stringanswer=fmt::to_string(42);
*/ template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
FMT_NODISCARD auto to_string(T value) -> std::string { // The buffer should be large enough to store the number including the sign // or "false" for bool. char buffer[max_of(detail::digits10<T>() + 2, 5)]; char* begin = buffer; return {buffer, detail::write<char>(begin, value)};
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.