1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-06-23 18:47:12 +02:00

Update fmt library.

This commit is contained in:
Sandu Liviu Catalin
2021-03-30 20:32:25 +03:00
parent 7a255f065f
commit eea5dd7743
12 changed files with 1875 additions and 1392 deletions

View File

@ -8,7 +8,7 @@
#ifndef FMT_FORMAT_INL_H_
#define FMT_FORMAT_INL_H_
#include <cassert>
#include <algorithm>
#include <cctype>
#include <climits>
#include <cmath>
@ -145,9 +145,9 @@ FMT_FUNC void format_error_code(detail::buffer<char>& out, int error_code,
error_code_size += detail::to_unsigned(detail::count_digits(abs_value));
auto it = buffer_appender<char>(out);
if (message.size() <= inline_buffer_size - error_code_size)
format_to(it, "{}{}", message, SEP);
format_to(it, "{}{}", ERROR_STR, error_code);
assert(out.size() <= inline_buffer_size);
format_to(it, FMT_STRING("{}{}"), message, SEP);
format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code);
FMT_ASSERT(out.size() <= inline_buffer_size, "");
}
FMT_FUNC void report_error(format_func func, int error_code,
@ -165,11 +165,8 @@ inline void fwrite_fully(const void* ptr, size_t size, size_t count,
size_t written = std::fwrite(ptr, size, count, stream);
if (written < count) FMT_THROW(system_error(errno, "cannot write to file"));
}
} // namespace detail
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
namespace detail {
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
template <typename Locale>
locale_ref::locale_ref(const Locale& loc) : locale_(&loc) {
static_assert(std::is_same<Locale, std::locale>::value, "");
@ -191,19 +188,18 @@ template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref loc) {
return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
.decimal_point();
}
} // namespace detail
#else
template <typename Char>
FMT_FUNC std::string detail::grouping_impl(locale_ref) {
template <typename Char> FMT_FUNC std::string grouping_impl(locale_ref) {
return "\03";
}
template <typename Char> FMT_FUNC Char detail::thousands_sep_impl(locale_ref) {
template <typename Char> FMT_FUNC Char thousands_sep_impl(locale_ref) {
return FMT_STATIC_THOUSANDS_SEPARATOR;
}
template <typename Char> FMT_FUNC Char detail::decimal_point_impl(locale_ref) {
template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) {
return '.';
}
#endif
} // namespace detail
FMT_API FMT_FUNC format_error::~format_error() FMT_NOEXCEPT = default;
FMT_API FMT_FUNC system_error::~system_error() FMT_NOEXCEPT = default;
@ -247,9 +243,6 @@ const typename basic_data<T>::digit_pair basic_data<T>::digits[] = {
{'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'},
{'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}};
template <typename T>
const char basic_data<T>::hex_digits[] = "0123456789abcdef";
#define FMT_POWERS_OF_10(factor) \
factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \
(factor)*1000000, (factor)*10000000, (factor)*100000000, \
@ -1070,10 +1063,14 @@ const char basic_data<T>::background_color[] = "\x1b[48;2;";
template <typename T> const char basic_data<T>::reset_color[] = "\x1b[0m";
template <typename T> const wchar_t basic_data<T>::wreset_color[] = L"\x1b[0m";
template <typename T> const char basic_data<T>::signs[] = {0, '-', '+', ' '};
#if __cplusplus < 201703L
template <typename T> constexpr const char basic_data<T>::hex_digits[];
template <typename T> constexpr const unsigned basic_data<T>::prefixes[];
template <typename T> constexpr const char basic_data<T>::left_padding_shifts[];
template <typename T>
const char basic_data<T>::left_padding_shifts[] = {31, 31, 0, 1, 0};
template <typename T>
const char basic_data<T>::right_padding_shifts[] = {0, 31, 0, 1, 0};
constexpr const char basic_data<T>::right_padding_shifts[];
#endif
template <typename T> struct bits {
static FMT_CONSTEXPR_DECL const int value =
@ -1228,7 +1225,7 @@ struct accumulator {
if (lower < n) ++upper;
}
void operator>>=(int shift) {
assert(shift == 32);
FMT_ASSERT(shift == 32, "");
(void)shift;
lower = (upper << 32) | (lower >> 32);
upper >>= 32;
@ -1307,7 +1304,7 @@ class bigint {
public:
bigint() : exp_(0) {}
explicit bigint(uint64_t n) { assign(n); }
~bigint() { assert(bigits_.capacity() <= bigits_capacity); }
~bigint() { FMT_ASSERT(bigits_.capacity() <= bigits_capacity, ""); }
bigint(const bigint&) = delete;
void operator=(const bigint&) = delete;
@ -1333,7 +1330,7 @@ class bigint {
int num_bigits() const { return static_cast<int>(bigits_.size()) + exp_; }
FMT_NOINLINE bigint& operator<<=(int shift) {
assert(shift >= 0);
FMT_ASSERT(shift >= 0, "");
exp_ += shift / bigit_bits;
shift %= bigit_bits;
if (shift == 0) return *this;
@ -1395,7 +1392,7 @@ class bigint {
// Assigns pow(10, exp) to this bigint.
void assign_pow10(int exp) {
assert(exp >= 0);
FMT_ASSERT(exp >= 0, "");
if (exp == 0) return assign(1);
// Find the top bit.
int bitmask = 1;
@ -1646,8 +1643,7 @@ struct fixed_handler {
// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox.
namespace dragonbox {
// Computes 128-bit result of multiplication of two 64-bit unsigned integers.
FMT_SAFEBUFFERS inline uint128_wrapper umul128(uint64_t x,
uint64_t y) FMT_NOEXCEPT {
inline uint128_wrapper umul128(uint64_t x, uint64_t y) FMT_NOEXCEPT {
#if FMT_USE_INT128
return static_cast<uint128_t>(x) * static_cast<uint128_t>(y);
#elif defined(_MSC_VER) && defined(_M_X64)
@ -1675,8 +1671,7 @@ FMT_SAFEBUFFERS inline uint128_wrapper umul128(uint64_t x,
}
// Computes upper 64 bits of multiplication of two 64-bit unsigned integers.
FMT_SAFEBUFFERS inline uint64_t umul128_upper64(uint64_t x,
uint64_t y) FMT_NOEXCEPT {
inline uint64_t umul128_upper64(uint64_t x, uint64_t y) FMT_NOEXCEPT {
#if FMT_USE_INT128
auto p = static_cast<uint128_t>(x) * static_cast<uint128_t>(y);
return static_cast<uint64_t>(p >> 64);
@ -1689,8 +1684,7 @@ FMT_SAFEBUFFERS inline uint64_t umul128_upper64(uint64_t x,
// Computes upper 64 bits of multiplication of a 64-bit unsigned integer and a
// 128-bit unsigned integer.
FMT_SAFEBUFFERS inline uint64_t umul192_upper64(uint64_t x, uint128_wrapper y)
FMT_NOEXCEPT {
inline uint64_t umul192_upper64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT {
uint128_wrapper g0 = umul128(x, y.high());
g0 += umul128_upper64(x, y.low());
return g0.high();
@ -1704,8 +1698,7 @@ inline uint32_t umul96_upper32(uint32_t x, uint64_t y) FMT_NOEXCEPT {
// Computes middle 64 bits of multiplication of a 64-bit unsigned integer and a
// 128-bit unsigned integer.
FMT_SAFEBUFFERS inline uint64_t umul192_middle64(uint64_t x, uint128_wrapper y)
FMT_NOEXCEPT {
inline uint64_t umul192_middle64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT {
uint64_t g01 = x * y.high();
uint64_t g10 = umul128_upper64(x, y.low());
return g01 + g10;
@ -2124,8 +2117,8 @@ FMT_ALWAYS_INLINE int remove_trailing_zeros(uint64_t& n) FMT_NOEXCEPT {
// The main algorithm for shorter interval case
template <class T>
FMT_ALWAYS_INLINE FMT_SAFEBUFFERS decimal_fp<T> shorter_interval_case(
int exponent) FMT_NOEXCEPT {
FMT_ALWAYS_INLINE decimal_fp<T> shorter_interval_case(int exponent)
FMT_NOEXCEPT {
decimal_fp<T> ret_value;
// Compute k and beta
const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent);
@ -2171,8 +2164,7 @@ FMT_ALWAYS_INLINE FMT_SAFEBUFFERS decimal_fp<T> shorter_interval_case(
return ret_value;
}
template <typename T>
FMT_SAFEBUFFERS decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT {
template <typename T> decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT {
// Step 1: integer promotion & Schubfach multiplier calculation.
using carrier_uint = typename float_info<T>::carrier_uint;
@ -2571,11 +2563,11 @@ int snprintf_float(T value, int precision, float_specs specs,
--exp_pos;
} while (*exp_pos != 'e');
char sign = exp_pos[1];
assert(sign == '+' || sign == '-');
FMT_ASSERT(sign == '+' || sign == '-', "");
int exp = 0;
auto p = exp_pos + 2; // Skip 'e' and sign.
do {
assert(is_digit(*p));
FMT_ASSERT(is_digit(*p), "");
exp = exp * 10 + (*p++ - '0');
} while (p != end);
if (sign == '-') exp = -exp;
@ -2593,54 +2585,6 @@ int snprintf_float(T value, int precision, float_specs specs,
}
}
// A public domain branchless UTF-8 decoder by Christopher Wellons:
// https://github.com/skeeto/branchless-utf8
/* Decode the next character, c, from buf, reporting errors in e.
*
* Since this is a branchless decoder, four bytes will be read from the
* buffer regardless of the actual length of the next character. This
* means the buffer _must_ have at least three bytes of zero padding
* following the end of the data stream.
*
* Errors are reported in e, which will be non-zero if the parsed
* character was somehow invalid: invalid byte sequence, non-canonical
* encoding, or a surrogate half.
*
* The function returns a pointer to the next character. When an error
* occurs, this pointer will be a guess that depends on the particular
* error, but it will always advance at least one byte.
*/
inline const char* utf8_decode(const char* buf, uint32_t* c, int* e) {
static const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
static const uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
static const int shiftc[] = {0, 18, 12, 6, 0};
static const int shifte[] = {0, 6, 4, 2, 0};
int len = code_point_length(buf);
const char* next = buf + len;
// Assume a four-byte character and load four bytes. Unused bits are
// shifted out.
auto s = reinterpret_cast<const unsigned char*>(buf);
*c = uint32_t(s[0] & masks[len]) << 18;
*c |= uint32_t(s[1] & 0x3f) << 12;
*c |= uint32_t(s[2] & 0x3f) << 6;
*c |= uint32_t(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 |= (s[1] & 0xc0) >> 2;
*e |= (s[2] & 0xc0) >> 4;
*e |= (s[3]) >> 6;
*e ^= 0x2a; // top two bits of each tail byte correct?
*e >>= shifte[len];
return next;
}
struct stringifier {
template <typename T> FMT_INLINE std::string operator()(T value) const {
return to_string(value);
@ -2656,7 +2600,8 @@ struct stringifier {
} // namespace detail
template <> struct formatter<detail::bigint> {
format_parse_context::iterator parse(format_parse_context& ctx) {
FMT_CONSTEXPR format_parse_context::iterator parse(
format_parse_context& ctx) {
return ctx.begin();
}
@ -2667,23 +2612,21 @@ template <> struct formatter<detail::bigint> {
for (auto i = n.bigits_.size(); i > 0; --i) {
auto value = n.bigits_[i - 1u];
if (first) {
out = format_to(out, "{:x}", value);
out = format_to(out, FMT_STRING("{:x}"), value);
first = false;
continue;
}
out = format_to(out, "{:08x}", value);
out = format_to(out, FMT_STRING("{:08x}"), value);
}
if (n.exp_ > 0)
out = format_to(out, "p{}", n.exp_ * detail::bigint::bigit_bits);
out = format_to(out, FMT_STRING("p{}"),
n.exp_ * detail::bigint::bigit_bits);
return out;
}
};
FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) {
auto transcode = [this](const char* p) {
auto cp = uint32_t();
auto error = 0;
p = utf8_decode(p, &cp, &error);
for_each_codepoint(s, [this](uint32_t cp, int error) {
if (error != 0) FMT_THROW(std::runtime_error("invalid utf8"));
if (cp <= 0xFFFF) {
buffer_.push_back(static_cast<wchar_t>(cp));
@ -2692,21 +2635,7 @@ FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) {
buffer_.push_back(static_cast<wchar_t>(0xD800 + (cp >> 10)));
buffer_.push_back(static_cast<wchar_t>(0xDC00 + (cp & 0x3FF)));
}
return p;
};
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 = transcode(p);
}
if (auto num_chars_left = s.data() + s.size() - p) {
char buf[2 * block_size - 1] = {};
memcpy(buf, p, to_unsigned(num_chars_left));
p = buf;
do {
p = transcode(p);
} while (p - buf < num_chars_left);
}
});
buffer_.push_back(0);
}
@ -2720,8 +2649,8 @@ FMT_FUNC void format_system_error(detail::buffer<char>& out, int error_code,
int result =
detail::safe_strerror(error_code, system_message, buf.size());
if (result == 0) {
format_to(detail::buffer_appender<char>(out), "{}: {}", message,
system_message);
format_to(detail::buffer_appender<char>(out), FMT_STRING("{}: {}"),
message, system_message);
return;
}
if (result != ERANGE)
@ -2770,12 +2699,13 @@ FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
if (_isatty(fd)) {
detail::utf8_to_utf16 u16(string_view(buffer.data(), buffer.size()));
auto written = detail::dword();
if (!detail::WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)),
u16.c_str(), static_cast<uint32_t>(u16.size()),
&written, nullptr)) {
FMT_THROW(format_error("failed to write to console"));
if (detail::WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)),
u16.c_str(), static_cast<uint32_t>(u16.size()),
&written, nullptr)) {
return;
}
return;
// Fallback to fwrite on failure. It can happen if the output has been
// redirected to NUL.
}
#endif
detail::fwrite_fully(buffer.data(), 1, buffer.size(), f);